目錄
Python中對延遲提供了友好的支持:即它提供了在需要的時候才產生結果的工具,而不是立即產生結果。下面介紹的函數生成器就是這種工具之一。
1:生成器函數的定義
定義:使用常規的def語句進行編寫,但是使用yield語句一次返回一個結果集,在每次結果產生之間掛起和恢復它們的狀態。
# 常規函數
def func1():
print('hello ')
return 'ixusy88'
ret = func1()
print(ret)
'''
結果:
hello
ixusy88
'''
print("*"*30)
# 生成器函數,把常規函數中的return替換爲yield
def func2():
print('hello ')
yield 'ixusy88'
ret = func2() # 並沒有執行函數,而是返回一個生成器對象
print(ret)
'''
結果:
<generator object func2 at 0x00000244C40CEF10>
'''
2:生成器函數的本質
生成器函數本質就是一個迭代器:函數中如果包含一條yield語句,那麼Python就會將它編譯爲生成器,這個函數不再是普通函數,而是作爲返回支持迭代協議的對象的函數,這個函數返回的對象會自動創建名爲__next__的方法接口。
"""
yield語句會掛起該函數並向調用者傳回一個值,同時會保留足夠的狀態使
函數能從它離開的地方繼續執行,當繼續時,函數在上一個yield傳回後立即繼續執行。
"""
def func1(N):
for i in range(N):
yield i**2
ret = func1(3) # 只要函數func1中有yield語句,就會返回一個支持迭代協議的對象
print(ret)
print('__iter__' in dir(ret))
print('__next__' in dir(ret))
"""
輸出結果:
<generator object func1 at 0x000002636160EF68>
True
True
"""
print("*"*30)
# ret 是一個支持迭代協議的對象,可以通過手工進行訪問
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
print(ret.__next__()) #
"""
0
1
4
Traceback (most recent call last):
File "D:\python\生成器函數.py", line 53, in <module>
print(ret.__next__()) # StopIteration
StopIteration
"""
print("*"*30)
ret = func1(5)
# ret 是一個支持迭代協議的對象,可以使用for循環來遍歷
for item in ret:
print(item)
"""
0
1
4
9
16
"""
3:小示例
# 斐波那契函數
#
def Fibonacci(N):
a,b,max_cnt = 0,1,N
while b <= max_cnt:
a,b = b,a+b
yield a
print('*'*30)
fib = Fibonacci(5)
print(fib)
for x in fib:
print(x)
'''
輸出結果:
<generator object Fibonacci at 0x000001A44C08EFC0>
1
1
2
3
5
'''
print('*'*30)
# 手工訪問
fib = Fibonacci(5)
print(fib.__next__())
print(fib.__next__())
print(fib.__next__())
print(fib.__next__())
print(fib.__next__())
print(fib.__next__())
'''
結果:
1
1
2
3
5
Traceback (most recent call last):
File "D:\python\生成器函數.py", line 119, in <module>
print(fib.__next__())
StopIteration
'''