在for循環中,每次yield值後,控制權就返回給for循環python
生成器相似於返回一個數組的函數。生成器有參數、能夠被調用,並生成值的序列。和函數一次返回整個數組不一樣,生成器每次只是生成一個值,這樣會佔用不多的內存,而且調用者能夠當即處理生成的值。歸納來講,生成器看起來像個函數,可是使用起來像個迭代器。shell
Python提供的,在須要時才生成結果的工具:
-生成器函數:
使用def定義,可是每次使用yield生成返回值值、掛起、在繼續運行。
-生成器表達式:
相似於列表推導,但不是建立一個結果列表,而是每次根據須要生成對象。數組
由於不管是生成器函數、仍是生成器表達式都不是一次生成一個結果列表,這樣能夠節省內存空間,並將計算時間以迭代協議的方式切分開。函數
生成器函數:yield和return
生成器函數和常規函數有點相似,都是使用def定義。當建立後,自動實現迭代協議。
常規函數會返回值並退出。而迭代器函數返回一個值後會自動掛起、而後再次執行。
生成器函數和常規函數之間的主要區別是前者yield一個值,後者返回一個值。yield會掛起函數,返回一個值給調用者。工具
生成器是和迭代協議綁在一塊兒的。可迭代的對象定義一個方法:__next__(),該方法要麼返回迭代器的下一個值,要麼拋出一個異常。對象
定義生成器的時候須要使用關鍵字:yield。blog
讓咱們來看個示例:內存
>>> def counter(n): print("counter()") while True: yield n print("increment n") n += 1 >>> c = counter(2) >>> c <generator object counter at 0x000000000246D480> >>> 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()返回一個迭代器對象rem
好比,下面的迭代器生成數字的立方值generator
>>> def cubic_generator(n): for i in range(n): yield i**3 >>> cg = cubic_generator(3) >>> cg <generator object cubic_generator at 0x0000000002A72CF0> >>> cg.next() 0 >>> cg.next() 1 >>> cg.next() 8 >>> cg.next() Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> cg.next() StopIteration >>>
在for循環中,每次yield值後,控制權就返回給for循環:
>>> for i in cubic_generator(5): print(i) 0 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 "<pyshell#54>", line 1, in <module> for i in cubic_generator(5): TypeError: 'int' object is not iterable >>> cubic_generator(5) 0 >>>
使用生成器的示例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) 0 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) 0 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)) <generator object <genexpr> 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() 0 >>> gen.next() 1 >>> gen.next() 8 >>> gen.next() 27 >>> gen.next() 64 >>> gen.next() Traceback (most recent call last): File "<pyshell#17>", line 1, in <module> 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'] >>>