Python3_迭代器和生成器
一、迭代器
1、迭代器協議的定義
物件必須提供一個__next__()方法,執行該方法要麼返回下一項值,要麼返回一個StopIteration異常錯誤。
2、可迭代物件
實現了迭代器協議的物件,即可以執行__next__()方法的物件。
字串、列表、元組、字典、集合、檔案物件都不是可迭代物件,因為它們都沒有next()方法。使用__itre__()方法可以將這些資料型別變為可迭代物件。
list01 = [1, 2, 3] iter_list = list01.__iter__() print(iter_list.__next__()) print(iter_list.__next__()) print(iter_list.__next__()) print(iter_list.__next__())
執行結果:
Traceback (most recent call last): 1 2 File "E:/Python學習/8、迭代器和生成器/迭代器.py", line 11, in <module> 3 print(iter_list.__next__()) StopIteration
通過上面的執行結果可知在執行到第四個print的時候Python給出了一個StopIteration錯誤,因為可迭代物件iter_list一共就三個引數
既然字串、列表、元組、字典、集合、檔案物件都不是可迭代物件,那為什麼這些資料型別都可以在for迴圈中被遍歷呢?接下去討論一下for迴圈的機制後即可知曉。
3、for迴圈的機制
- 在使用for迴圈對資料型別進行遍歷的時候實際上是呼叫了__iter__()方法將資料型別變為了可迭代物件
- 在for迴圈將可迭代物件中的元素全部遍歷完後也會給出一個StopIteration錯誤,但for迴圈遇到StopIteration錯誤後就結束了對可迭代物件的遍歷
for迴圈機制使用while迴圈體現:
list01 = [1, 2, 3] init_num = 0 iter_list = list01.__iter__() while init_num < len(list01): init_num += 1 print(iter_list.__next__())
執行結果:
1
2
3
4、迭代器的特性
- 可迭代物件只能被迭代一次
二、生成器
1、生成器的定義
生成器就是一個數據型別,但是這個資料型別可以自動實現迭代器協議
2、生成器的表達形式
生成器的表達形式有兩種:一種是生成器函式,另一種是生成器表示式
2.1、生成器函式
在函式中使用yield語句替換return函式,當函式碰到了yield時會返回一個相應的值,並記錄當前函式執行的狀態,在下次呼叫函式的時候會從當前狀態執行函式;如:
def test(): print("這是1") yield 1 print("這是2") yield 2 print("這是3") yield 3 l = test() print(l.__next__()) print(l.__next__()) print(l.__next__())
執行結果:
這是1
1
這是2
2
這是3
3
send()方法:
send()方法和__next__方法實現的功能類似,都是取出生成器中的值,但send()方法需要傳遞一個引數,可以將該引數傳遞給yield並賦值給一個變數,如:
def test(): f = yield 1 print(f) yield 2 t = test() print(t.__next__()) t.send("yield一個1")
執行結果:
1 yield一個1
2.1.2、生成器函式和普通函式比較的好處
生成器函式無需完整生成一個列表,yield一個至即可處理一個值,簡約了記憶體空間。
2.2、生成器表示式
2.2.1、三元表示式
num = 5 res = "這是為True時返回的值" if num == 5 else "這是為False時返回的值" print(res)
執行結果:
這是為True時返回的值
在上面的三元表示式中的三元指的是:
- "這是為True時返回的值"
- if num == 5
- else "這是為False時返回的值"
2.2.2、列表解析式
l = ["列表元素%s" %i for i in range(5)] print(l)
執行結果:
['列表元素0', '列表元素1', '列表元素2', '列表元素3', '列表元素4']
上面的解析式就相當於下面的程式碼:
l = [] for i in range(5): l.append("列表元素%s" %i) print(l)
列表解析式還可以和三元表示式結合在一起使用
l = ["列表元素%s" %i for i in range(10) if i > 5] print(l)
執行結果:
['列表元素6', '列表元素7', '列表元素8', '列表元素9']
列表解析式的缺點:
當在資料較大的情況下會佔用大量的記憶體空間,因為列表解析式最後輸出的結果直接存放在記憶體中
2.2.3、生成器表示式:
使用方法:
將列表解析式中的方括號改為小括號即可,如
l = ("列表元素%s" %i for i in range(10) if i > 5) print(l)
執行結果:
<generator object <genexpr> at 0x00A0D770>
生成器表示式相比較於列表解析式的優點在於佔用的記憶體空間小,因為生成器表示式是直接生成一個迭代器而不是一個存放在記憶體中的列表
3、生成器的特性
- 延遲計算,一次只返回一個結果
- 提高程式碼的可讀性