博主前言:
「2020本來是充滿希望,收穫幸福的一年。可沒想到這一年的開始就如此的慘烈、痛苦。在此,博主真誠的祝福那些身處在抗疫一線的白衣天使們能夠平穩健康,給他(她)們致以最崇高的敬意」
這篇博客講述Python中的迭代器和生成器,內容較抽象,希望讀者結合代碼好好理解。
1. 迭代器
迭代是重複反饋過程的活動,其目的通常是爲了逼近所需目標或結果。
每一次對過程的重複稱爲一次“迭代”,而每一次迭代得到的結果會作爲下一次迭代的初始值。
在計算機中重複執行程序中的循環,直到滿足某條件爲止,亦稱爲迭代。
1.1 iter()
Python語言中,在定義一個類時,如果在類中定義了iter()函數,
那麼這個類就是可迭代的類,
由這個類所實例化的對象就是可迭代的對象。
在Python語言中,可調用collections模塊的Iterable中的isinstance()函數判斷當前對象是否可迭代。
from collections import Iterable
class IterableClass(object):
"""定義一個可迭代的類"""
def __init__(self,name,nubmer): # 構造函數
self.name = name
self.number = nubmer
def __iter__(self): # 定義iter函數,僞代碼
pass
def main():
test = IterableClass("tomato",2020)
print("判斷test是否可迭代:%s" % isinstance(test,Iterable))
if __name__ == '__main__':
main()
當我們運行上述代碼時,結果如下:
可當我們把定義的iter函數註釋掉後再運行時代碼,結果會大相徑庭。
# def __iter__(self): # 定義iter函數,僞代碼
# pass
由此可知:
當類中定義了iter函數時,那麼由該類實例化的對象是可迭代的。
當類中沒有定義iter函數時,由該類實例化的對象就不可迭代(例整型)。
1.2 next()
在類定義時,同時定義了iter函數和next函數的類,其所實例化的對象稱爲迭代器對象。
可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator
在Python語言中,可調用collections模塊的Iterable中的isinstance()函數判斷當前對象是否爲迭代器對象(代碼實現如上段)
接下來,我們在定義一個迭代器類。
from collections import Iterable
class IteratorClass(object):
"""定義一個迭代器類"""
def __init__(self): # 構造函數
self.g_number = 0
self.name = list()
self.number = list()
def AddMemmber(self,name,number): # 添加數據
self.name.append(name)
self.number.append(number)
def __iter__(self):
return self
def __next__(self):
if len(self.name) > self.g_number:
name = self.name[self.g_number]
number = self.number[self.g_number]
self.g_number += 1
return "姓名:"+name+", "+"學號:"+str(number)
else:
raise StopIteration
def main():
test = IteratorClass()
test.AddMemmber("tomato",2020)
test.AddMemmber("potato",2021)
test.AddMemmber("konato",2022)
for member in test:
print(member)
if __name__ == '__main__':
main()
運行上段代碼,結果如以下圖示。
主線程執行順序:
- 定義一個迭代器類IteratorClass,實例化一個對象test
- 使用AddMemmber函數,將個人信息加入庫中
- 執行迭代運算,從test對象中取出每個人的個人信息
- 在迭代運算中(即for循環),迭代器對象會自動調用類中的iter函數,iter函數的返回值是一個迭代器。在此代碼中,test對象的iter函數的返回值爲自身,因爲test對象自身就是一個迭代器對象
- 調用迭代器的next函數來取值,一次迭代調用一次next函數。
- Python中的迭代器協議就是每次調用next函數的對象會前進到下一個結果,
而在迭代器中的值取完時則會拋出StopIteration異常。
2. 生成器
生成器是一種特殊的迭代器。
例:
列表生成式: | [ x*2 for x in range()10 ] |
---|---|
列表生成器: | ( x*2 for x in range()10 ) |
2.1 yield
在函數定義時,若函數體中存在關鍵字yield,
那麼該函數就是一個生成器模板,
調用該函數,就是創建一個生成器對象。
yield後面是誰,就把誰return,再次調用時從上次yield的地方繼續執行。
最後,我們用代碼來實現一下黃體字的編程邏輯:
g_number = 10 # 定義一個全局變量g_number
def generator(): # 定義一個生成器模板
global g_number
while True:
print("----- 1 -----")
print("當前number的值爲:",g_number)
yield g_number
g_number -= 1
print("當前number的值爲:",g_number)
print("----- 2 -----")
def main():
test = generator()
next(test)
if __name__ == '__main__':
main()
因爲迭代器都能通過調用next()函數使其運行,
生成器是一種特殊的迭代器,
所以這裏的生成器對象test同樣調用next函數來運行。
運行上述代碼,結果如以下圖示:
當我們修改main函數,將next函數運行兩次,這時得到的結果如以下圖示:
def main():
test = generator()
next(test)
next(test)
由此,我們可以看出在函數定義中,
yield後面是誰,就把誰return,再次調用時從上次yield的地方繼續執行,
當再次運行到yield時,再次將yield後面的值return。