首先說明一下生成器也是迭代器,也有迭代器的那些優點。
那為什麼要生成器呢?因為到目前為止都 不是你寫的迭代器,都是別人定義好的。那如何自己去造乙個迭代器呢?下面的內容就會給你答案。
想要自己造乙個迭代器,我們可以根據迭代器的特徵(只要乙個物件有__iter__
和__next__
方法那它就是迭代器),自己定義乙個類,然後定義乙個__iter__()
和__next__()
, 然後這個類例項化的物件就是乙個迭代器啦。
但是這樣寫太麻煩啦!何況我們現在還沒有學到類的知識,怎麼辦?給你乙個魔法棒,讓你快速優雅高效地造乙個迭代器。
第一種自造迭代器的方法就是使用yield
關鍵字。具體怎麼實現呢?
非常簡單,如下所示:
def上面的寫法非常類似於函式的定義,相當於把return換成了g():
print("
hey~ 生成器")
yield 1
yield
(當然,並沒有這麼簡單)。
此時,我執行g()
返回的就是乙個生成器。就是這麼簡單。
ret =g()但是這裡有個特別需要注意的地方,也是與函式最明顯的區別:print(ret) #
輸出
我們執行g()
的時候,並沒有列印"hey~ 生成器"
,就像函式沒執行一樣。
這也是生成器乙個非常重要的特點,那就是你執行g()
返回的是乙個生成器,同時只有在迭代它(呼叫它的__next__()
)的時候它才開始執行內部**,碰到yield
關鍵字就返回yield後面的值並停止。
print(ret.__next__()) $print(next(ret))輸出:
hey~生成器當然for迴圈它也是可以的:1
for i in輸出:ret:
print(i)
hey~生成器1
yield
還可以多次執行,這與return也有區別。
def此時,你執行下g2():
print("
hey~ 生成器1")
yield 1
print("
hey~ 生成器2")
yield 2ret = g2()
next(ret)
,會列印"嘿!生成器1"
,然後返回乙個1
,再執行一次next(ret)
,會列印出"嘿!生成器2"
,然後返回乙個2
。
(next(ret))#輸出
hey~生成器1
1print
(next(ret))#輸出
hey~生成器2
2
return
之後函式就徹底結束了:
deftest_return():
return 1
return 2 #
永不執行
return 3 #
永不執行
yield
之後可以儲存函式的執行狀態,下次繼續執行:
def下面的例子中,使用test_yield():
yield 1
yield 2 #
下次next()後執行
yeild 3 #
下次next()後執行
return
時,只能返回0
。
def使用test_return2():
for i in range(10):
return i #
只能返回0,函式就結束了
yield
能夠依次返回0~9
。
deftest_yield2():
for i in range(10):
yield i #
每呼叫一次next()就會一次彈出0~9
yield
把函式變成了生成器(生成器就是迭代器)。
為函式封裝好了__iter__
和__next__
方法,把函式的執行結果做成了迭代器。
遵循迭代器的取值方式 —obj.__next__()
,觸發的是函式的執行。函式暫停與繼續執行的狀態都是由yield
儲存的。
倒計時的例子:
def分析下面語句的執行過程:countdown(n):
print("
倒計時開始")
while n >0:
yield
n n -= 1
print("
發射")
g = countdown(5)呼叫print(g.__next__()) #
列印"倒計時開始" 返回5 (此時n=5)
print(g.__next__()) #
返回4 (此時n=4)
print(g.__next__()) #
返回3 (此時n=3)
print(g.__next__()) #
返回2 (此時n=2)
print(g.__next__()) #
返回1 (此時n=1)
print(g.__next__()) #
列印"發射" 丟擲stopiteration異常(此時n=0)
__next__()
時函式執行內部**,到yield
關鍵字時暫停:
g = countdown(5)輸出:print(g.__next__())
倒計時開始生成器也是不能後退:5
g = countdown(5)輸出:print(g.__next__
())print(g.__next__
())for i in
g:
print(i)
倒計時開始54每呼叫一次-- for --32
1發射
countdown(5)
得到的都是不同的生成器
for i in countdown(5):輸出:(i)
for i in copuntdown(5):
print(i)
5下面的例子也是一樣,每一次print中5
countdown(5)
都是乙個全新的生成器,所以列印出來的值都是5
。
print(countdown(5).__next輸出:())print(countdown(5).__next
())print(countdown(5).__next())
5我們之前學過列表推導式,是這樣寫的:55
>>> [i for i in range(10)]這樣來得到乙個元素數量較小的列表是非常方便的,但是如果要建立乙個元素數量巨大的列表,就不那麼友好了[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [i for i in range(10000000000)]這個時候只要把...
換成()
就把列表推導式 變成了生成器表示式,得到的就是乙個生成器物件,就是這麼神奇。
這就是第二種自造迭代器的方法。
>>> (i for i in range(10))我們可以直接使用for迴圈遍歷上面得到的生成器:at 0x101fef6d0>
>>> for i in (i for i in range(10)):這樣我們就能自信的建立個10000000000元素的生成器,不擔心記憶體會爆了。...
(i)... 01
2345
6789
>>> (i for i in range(10000000000))最後的總結:at 0x101fef728>
python語法面試題 python面試題
1.去重,集合 集合的乙個重要特點是 自動去除重複的值 li 1,2,3,1,1,2,2,3,3 去除重複的元素 set set li 轉換為集合,因為集合會自動去重。print set li list set 將集合轉換為列表print li 2.生成器 規則 生成器函式,或者生成器表示式,在呼叫...
C 面試題之i 面試題
i 面試題1.cpp 中國台灣某著名防毒軟體公司2005年10月面試題 int i 3,j 4 i?i j printf d d n i,j a.3 3 b.4 4 c.3 4 d.4 3 答案b i 面試題2.cpp 中國某著名計算機金融軟公司2005年面試題 int x 1,j 2 int k ...
C 面試題之sizeof面試題
sizeof面試題1.cpp what is the output of the following code?美國某著名計算機軟硬體公司面試題 include include include using namespace std structa structb int main 解析 ss1是乙...