1. 生成器初始
什么是生成器?這個概念比較模糊,各種文獻都有不同的理解,但是核心基本相同。生成器的本質就是迭代器,在python社區中,大多數時候都把迭代器和生成器是做同一個概念。不是相同么?為什么還要創建生成器?生成器和迭代器也有不同,唯一的不同就是:迭代器都是Python給你提供的已經寫好的工具或者通過數據轉化得來的,(比如文件句柄,iter([1,2,3])。生成器是需要我們自己用python代碼構建的工具。最大的區別也就如此了
1.1 生成器的構建
在python中有三種方式來創建生成器:
-
- 通過生成器函數
-
- 通過生成器推導式
- 3. python內置函數或者模塊提供(其實1,3兩種本質上差不多,都是通過函數的形式生成,只不過1是自己寫的生成器函數,3是python提供的生成器函數而已)
1.2 生成器函數
我們先看一個很簡單的函數:
def func():
print('in func1')
return 22
func()
print(func())
>>>
in func1
in func1
22
將函數中的return換成yield,這樣func就不是函數了,而是一個生成器函數
def func():
print('in func1')
yield 22 #函數中存在yield,那么這個函數就是一個生成器函數
func()
print(func())
>>>
<generator object func at 0x0000018C4DED2E48>
運行的結果和最上面的不一樣,為什么呢?? 由於函數中存在yield,那么這個函數就是一個生成器函數.
1.2.1 生成器的取值
生成器的本質就是迭代器.迭代器如何取值,生成器就如何取值。所以我們可以直接執行next()來執行以下生成器
def func():
print('in func1')
yield 22
print(func())
print(next(func()))
>>>
<generator object func at 0x000002CF72A02EC8>
in func1
22
1.2.2 return and yield 區別
- return 函數中只存在一個return結束函數,並且給函數的執行者返回值。
- yield 只要在函數中有yield那么它就是生成器函數而不是函數了。
生成器函數中可以存在多個yield,yield不會結束生成器函數,一個yield對應一個next
舉列
我們來看一下這個需求:老男孩向樓下賣包子的老板訂購了10000個包子.包子鋪老板非常實在,一下就全部都做出來了
def eat():
lst = []
for i in range(1,10000):
lst.append('包子'+str(i))
return lst
print(eat())
這種方式是可以,但是是個消耗內存的方法;但是我們由於學生沒有那么多,只吃了2000個左右,剩下的8000個,就只能占着一定的空間,放在一邊了。如果包子鋪老板效率夠高,我吃一個包子,你做一個包子,那么這就不會占用太多空間存儲了,完美..
def eat():
for i in range(1,10):
yield '包子'+str(i)
e = eat()
for i in range(5):
print(next(e))
# 多次next包子的號碼是按照順序記錄的。
>>>
包子1
包子2
包子3
包子4
包子5
這兩者的區別
- 第一種是直接把包子全部做出來,占用內存。
- 第二種是吃一個生產一個,非常的節省內存,而且還可以保留上次的位置。
1.2.3 yield from
提供一種可以直接把可迭代對象中的每一個數據作為生成器的結果進行返回
# 對比yield 與 yield from
def func():
lst = ['衛龍','老冰棍','北冰洋','牛羊配']
yield lst
g = func()
print(g)
print(next(g)) # 只是返回一個列表
def func():
lst = ['衛龍','老冰棍','北冰洋','牛羊配']
yield from lst
g = func()
print(g)
# 他會將這個可迭代對象(列表)的每個元素當成迭代器的每個結果進行返回。
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
yield from ['衛龍','老冰棍','北冰洋','牛羊配']
等同於:
yield '衛龍'
yield '老冰棍'
yield '北冰洋'
yield '牛羊配'
'''
