python生成器小結

2021-08-08 03:00:07 字數 3711 閱讀 7019

通過列表生成式,我們可以直接建立乙個列表。但是,受記憶體限制,列表的容量也是有限的,當我們建立乙個包含100w個元素的列表,不僅占用記憶體空間比較多,而且假如我們只需要訪問前幾個元素,那麼後面絕大部分元素占用的空間都浪費了。

如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈使用的過程中不斷推算後續的元素呢,這樣就不必建立完整的list,浪費空間。

在python中,這種一邊迴圈一遍計算的機制,稱為生成器(generator)。

首先,來看一下列表的建立:

l = [x for x in range(8)]

print(l)

參照上面**,只要做如下改動,就建立乙個生成器:

# 01. 將列表生成式中的改為()

g = (x for x in range(3))

print(g)

列印結果為:

object

at 0x102967ca8>

如上,就建立了乙個生成器物件。

直接列印g相當於輸出的是物件位址,那麼該如何取其中的元素呢?

通過next(g)或g.next()方式進行取值

# 列印g的值,通過next()函式 獲取生成器的下乙個返回值

print(g.__next__())

print(next(g))

print(next(g))

print(next(g))

print(next(g))

輸出為:

012

traceback (most recent call

last):

file "/users/***/project/pycharmprojects/**/generator_test.py", line 11, in

print(next(g))

stopiteration

可以看到,這樣可以取到生成器的值,不過當角標越界後,會跑出stopiteration異常,可以通過監聽次異常來完成取值。

try:

print(g.__next__())

print(next(g))

print(next(g))

print(next(g))

except stopiteration as e:

print('取值完成')

輸出為:

012

取值完成

通過for迴圈完成取值

for x in g:

print(x)

同樣可以完成對g的取值

只要函式中有yield關鍵字,該函式就不是普通函式了,而是乙個生成器物件。如果再通過函式名直接呼叫,是無效的。

def

create_num2

(number):

a, b = 0, 1

for x in range(number):

yield b

a, b = b, a + b

通過**,看一下生成器的呼叫過程。

def

create_num2

(number):

print('create_num2 start')

a, b = 0, 1

for x in range(number):

# 遇到yield程式暫停,同時把後面的值返回

# 如果再次用next()進行呼叫,就會從上次yiled暫停的地方繼續執行

print('....1....')

yield b

print('....2....')

a, b = b, a + b

print('....3....')

print('create_num2 stop')

a = create_num2(10)

print('*' * 10 + '第一次呼叫yiled物件' + '*' * 10)

print(next(a))

print('*' * 10 + '第二次呼叫yiled物件' + '*' * 10)

print(next(a))

輸出結果為:

*****

*****第一次呼叫yiled物件*****

*****

create_num2 start

....1....

1*****

*****第二次呼叫yiled物件*****

*****

....2....

....3....

....1....

1

執行流程:

1. 執行 a = create_num2(10),建立生成器物件a

2. 當呼叫next(a)的時候,才會執行到函式中,依次列印 start …1…

3. 當執行到yield b時,會將程式暫停,同時把後面的值(b)返回

4. 接收b的返回,此時為1,so 列印1

5. 再次執行next(a)的時候,會從上次yield暫停的地方繼續執行,所以先列印…2… …3…,然後再次進入for迴圈,列印…1…,又遇到yield,暫停中,同時返回b的值

6. 接收b的值,並列印

在呼叫生成器函式時,也可以對其進行傳值,如下:

# 定義乙個yield物件,並且增加temp = yield i

deftest

(): i = 0

while i < 5:

temp = yield i

print(temp)

i += 1

t = test()

# 首次呼叫

print(t.__next__())

# 第二次呼叫

print(t.__next__())

# 第三次呼叫

print(t.send('python'))

輸出為:

0

none

1python

2

執行流程:

1. 首次呼叫,因為temp = yield i為賦值語句,先執行右邊**,當執行到yield時,暫停執行,並把i返回回去,so ,列印 0

2. 第二次呼叫,從yield i開始,可以把yiedl i作為乙個**塊,賦值給temp,此時沒傳值,所以列印為none,其他正常執行

3. 第三次呼叫,通過send方法,傳遞引數,這時候相當於把引數賦值給temp,所以列印結果為python,其他流程正常執行

ps:在第一次呼叫生成器的時候不能傳參,否則會跑出異常,如下:

typeerror: can't send non-none value to a just-started generator
首次必須先呼叫next()或send(none)。

生成器是這樣乙個函式,它記住上一次返回時函式體中的位置。對生成器的第二次(n)呼叫跳轉至該函式中間,而上次呼叫的所有區域性變數都保持不變

生成器特點

節約記憶體

迭代到下一次的呼叫時,所使用的引數都是第一次所保留下的,也就是說,在整個所有函式呼叫的引數都是第一次呼叫時保留的,而不是新建立的。

python 生成器作用 Python生成器

生成器介紹 在函式內部包含yield關鍵字,那麼該函式執行的結果是生成器,生成器就是迭代器。生成器的功能 把函式結果做成迭代器 以一種優雅的方式封裝好iter,next 提供了一種自己定義迭代器的方式。使用生成器建立乙個迭代器 def a print a yield 11 使用yield,執行後返回...

python生成器好處 Python生成器筆記

python中三大器有迭代器,生成器,裝飾器,本文主要講述生成器。主要從生成器的概念,本質,以及yield關鍵字的使用執行過程。本質 生成器是一類特殊的迭代器,使用了yield關鍵字的函式不再是函式,而是生成器。使用了yield的函式就是生成器 1.yield關鍵字有兩點作用 1.1 yield語句...

python生成器函式 Python 生成器函式

一 生成器 生成器指的是生成器物件,可由生成器表示式得到,也可使用 yield 關鍵字得到乙個生成器函式,呼叫這個函式得到乙個生成器物件 生成器物件,是乙個可迭代物件,是乙個迭代器 生成器物件,是延遲計算 惰性求值的 1.1 生成器函式 函式體重包含 yield 語句的函式,就是生成器函式,呼叫後返...