在for循環中,每次yield值後,控制權就傳回給for循環
生成器類似于傳回一個數組的函數。生成器有參數、可以被調用,并生成值的序列。和函數一次傳回整個數組不同,生成器每次隻是生成一個值,這樣會占用很少的記憶體,并且調用者可以立即處理生成的值。概括來說,生成器看起來像個函數,但是使用起來像個疊代器。
Python提供的,在需要時才生成結果的工具:
-生成器函數:
使用def定義,但是每次使用yield生成傳回值值、挂起、在繼續運作。
-生成器表達式:
類似于清單推導,但不是建立一個結果清單,而是每次根據需要生成對象。
因為無論是生成器函數、還是生成器表達式都不是一次生成一個結果清單,這樣可以節省記憶體空間,并将計算時間以疊代協定的方式切分開。
生成器函數:yield和return
生成器函數和正常函數有點類似,都是使用def定義。當建立後,自動實作疊代協定。
正常函數會傳回值并退出。而疊代器函數傳回一個值後會自動挂起、然後再次執行。
生成器函數和正常函數之間的主要差別是前者yield一個值,後者傳回一個值。yield會挂起函數,傳回一個值給調用者。
生成器是和疊代協定綁在一起的。可疊代的對象定義一個方法:__next__(),該方法要麼傳回疊代器的下一個值,要麼抛出一個異常。
定義生成器的時候需要使用關鍵字:yield。
讓我們來看個示例:
>>> def counter(n):
print("counter()")
while True:
yield n
print("increment n")
n += 1
>>> c = counter(2)
>>> c
>>> next(c)
counter()
2
>>> next(c)
increment n
3
>>> next(c)
increment n
4
>>> c.next()
increment n
5
>>> c.next()
increment n
6
>>>
1.關鍵字yield表明該函數不是一個正常函數,而是一個疊代器函數。
2.生成一個疊代器的執行個體,和調用正常函數類似。但是調用的時候并不真正執行函數代碼。
3.counter()傳回一個疊代器對象
比如,下面的疊代器生成數字的立方值
>>> def cubic_generator(n):
for i in range(n):
yield i**3
>>> cg = cubic_generator(3)
>>> cg
>>> cg.next()
>>> cg.next()
1
>>> cg.next()
8
>>> cg.next()
Traceback (most recent call last):
File "", line 1, in
cg.next()
StopIteration
>>>
在for循環中,每次yield值後,控制權就傳回給for循環:
>>> for i in cubic_generator(5):
print(i)
1
8
27
64
>>>
如果用return代替yield:
>>> def cubic_generator(n):
for i in range(n):
return i**3
>>> for i in cubic_generator(5):
print(i)
Traceback (most recent call last):
File "", line 1, in
for i in cubic_generator(5):
TypeError: 'int' object is not iterable
>>> cubic_generator(5)
>>>
使用生成器的示例1:
>>> def fib():
limit = 10
count = 0
a,b = 0,1
while True:
yield a
a,b = b,a+b
if (count == limit):
break
count += 1
>>> for i in fib():
print(i)
1
1
2
3
5
8
13
21
34
55
>>>
使用生成器實作斐波納契數列:
>>> def fib(max):
a,b = 0,1
while a < max:
yield a
a,b = b,a+b
>>> for i in fib(500):
print (i)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
>>> list(fib(500))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
>>>
生成器表達式: 可推導的疊代器
疊代器和清單推導相結合,形成了一個新特性:生成器表達式。
生成器表達式和清單表達式類似,但是前者被小括号包含着,後者是用方括号包含的。
>>> #清單推導
>>> [x**3 for x in range(5)]
[0, 1, 8, 27, 64]
>>>
>>> #生成器表達式
>>> (x**3 for x in range(5))
at 0x0000000002BE0798>
>>>
>>> list(x**3 for x in range(5))
[0, 1, 8, 27, 64]
>>>
>>> gen=(x**3 for x in range(5))
>>> gen.next()
>>> gen.next()
1
>>> gen.next()
8
>>> gen.next()
27
>>> gen.next()
64
>>> gen.next()
Traceback (most recent call last):
File "", line 1, in
gen.next()
StopIteration
>>>
生成器:函數 vs 表達式
相同的疊代可以用生成器函數或生成器表達式實作。二者都可以自動疊代或手動疊代。
>>> gen = (c*5 for c in 'pyhton')
>>> list(gen)
['ppppp', 'yyyyy', 'hhhhh', 'ttttt', 'ooooo', 'nnnnn']
>>>
>>> def gen(x):
for c in x:
yield c*5
>>> g=gen('python')
>>> list(g)
['ppppp', 'yyyyy', 'ttttt', 'hhhhh', 'ooooo', 'nnnnn']
>>>