python -- 生成器

在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']
>>> 
相關文章
相關標籤/搜索