您好!此筆記的文本和代碼以網盤形式分享於文末!
因個人能力有限,錯誤處歡迎大家交流和指正!基礎部分內容簡單,但多且零散!
Python迭代器和生成器 | ||
迭代:可以將某個數據集內的數據“一個挨着一個的取出來”,就叫做迭代。 | ||
可迭代數據類型:字符串、列表、元組、字典、集合 | ||
可迭代協議:可迭代協議的定義非常簡單,就是內部實現了__iter__方法 | ||
迭代器:迭代器是一個可以記住遍歷的位置的對象,迭代器遵循迭代器協議:必須擁有__iter__方法和__next__方法。節省內存 | ||
生成器:自己實現迭代器的功能代碼叫生成器,在調用生成器運行的過程中,每次遇到 yield 時函數會暫停並保存當前所有的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。 | ||
生成器的本質:就是迭代器,特點是惰性運算,開發者自定義; | ||
生成器函數:一個包含yield關鍵字的函數就是一個生成器函數; | ||
生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表 | ||
生成器優點:延遲計算,一個返回一個結果,不會一次性生成所有結果,對於大數據處理很有意義。並且提高代碼的可讀性 | ||
用法 | 栗子 | 結果 |
迭代 | # 將數據集內的元素一個接一個取出來的過程叫做迭代 for i in [1, 2, 3, 'a']: print(i) |
1 2 3 a |
可迭代的數據類型 | # 字符串、列表、元組、字典、集合都是可迭代的 from collections import Iterable s1 = '12ab' li1 = [1, 2, 'a', 'b'] tu1 = (1, 2, 'a', 'c', ) di1 = {'a': 1, 'b': 2, } se1 = {1, 2, 3, 4} a = 123456789 print(isinstance(s1, Iterable)) print(isinstance(li1, Iterable)) print(isinstance(tu1, Iterable)) print(isinstance(di1, Iterable)) print(isinstance(se1, Iterable)) print(isinstance(a, Iterable)) |
True True True True True False |
可迭代協議: 內部實現了__iter__方法 |
# 對比可迭代數據類型中都有實現__iter__方法 print(dir(s1)) print(dir(tu1)) print(dir(a)) |
|
不同數據類型 中__iter__方法的包含 字典和集合的無序特性 其無__setstate__方法 |
print(set(dir(s1.__iter__())) - set(dir(s1))) print(set(dir(li1.__iter__())) - set(dir(li1))) print(set(dir(tu1.__iter__())) - set(dir(tu1))) print(set(dir(di1.__iter__())) - set(dir(di1))) print(set(dir(se1.__iter__())) - set(dir(se1))) |
{'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__'} {'__next__', '__length_hint__'} |
三個方法的使用和介紹 | iter_1 = li1.__iter__() # 獲取迭代器中元素的長度 print(iter_1.__length_hint__()) # 根據索引值指定位置開始迭代 print(iter_1.__setstate__(2)) # 一個接一個的取值 print(iter_1.__next__()) print(iter_1.__next__()) |
4 None a b |
__next__方法 及其異常處理 |
# __next__() 方法會由於無元素可取報異常 # 使用異常處理機制來處理掉異常 iter_1 = li1.__iter__() while True: try: item = iter_1.__next__() print(item) except StopIteration: break |
1 2 a b |
range() 是可迭代對象 但不是迭代器 |
from collections import Iterator # range()關於iter和next方法測試 # 在range()執行後的內部是否有next和iter方法 print('__next__' in dir(range(12))) print('__iter__' in dir(range(12))) # 是否可迭代 print(isinstance(range(12), Iterable)) # 是否是迭代器 print(isinstance(range(12), Iterator)) |
False True True False |
生成器函數 | # 生成器函數 import time def genrator_func(): a = 1 print('定義a 變量') yield a # 暫停,等待下次next()方法的執行 b = 2 print('定義b變量') yield b c = 3 print('定義c變量') yield c gen1 = genrator_func() print('g1: ', gen1) print('-'*17) print(next(gen1)) time.sleep(1) print(next(gen1)) |
g1: <generator object genrator_func at 0x000001BB7B30F990> ----------------- 定義a 變量 1 定義b變量 2 |
生成器函數二 | def produce(): """ 生產定製手模 月生產力最多13個 """ for i in range(13): yield '生產了第%d個手模' % i produce_g = produce() # 接受客戶定製訂單 print('請輸入訂單數量:') num = int(input()) if num > 10: print('抱歉超過本月生產力,請返回重新輸入!') j = 0 for i in produce_g: if j < num <= 10: print(i) j += 1 else: break # 樣品生產 print('樣品展示:', '\n', produce_g.__next__()) print(next(produce_g)) |
請輸入訂單數量: 11 抱歉超過本月生產力,請返回重新輸入! 樣品展示: 生產了第1個手模 生產了第2個手模 |
生成器監聽文件輸入列子 | ||
.send應用 時間間隔可更清晰的 看到運行順序 |
import time def generator(): print('開始') content = yield '返回1' print('第一個yield的值:', content) print('Two') content2 = yield '返回2' print('第二個yield的值:', content2) print('Three') content3 = yield "返回3" print('第三個yield的值:', content3) print('four') yield '第4次返回' g = generator() # 第一次運行只能使用next或send(None) print(g.send(None)) print('\n') time.sleep(6) # send 作用相當於next方法並將傳遞參數爲 yield的返回值 print(g.send('第2次傳入參數')) print('\n') time.sleep(6) # next方法 相當於 send(None) 即 temp = None print(g.__next__()) print('\n') time.sleep(6) # 最後一個yield不能接受外部的值 print(g.send(None)) |
開始 返回1 第一個yield的值: 第2次傳入參數 Two 返回2 第二個yield的值: None Three 返回3 第三個yield的值: None four 第4次返回 |
計算移動平均值 | import time def averager(): total = 0.0 count = 0 average = None while True: print("第%d次執行" % count) term = yield average total += term count += 1 average = total / count print('第%d次接收的term值爲:' % count) print(term) g_avg = averager() print('第一次調用send') print('第一次生成器yield返回值爲', next(g_avg)) print('\n') time.sleep(6) print('第二次調用send') print('第二次生成器yield返回值爲', g_avg.send(15)) print('\n') time.sleep(6) print('第三次調用send') print('第三次生成器yield返回值爲', g_avg.send(30)) print('\n') time.sleep(6) print('第四次調用send') print('第四次生成器yield返回值爲', g_avg.send(10)) |
第一次調用send 第0次執行 第一次生成器yield返回值爲 None 第二次調用send 第1次接收的term值爲: 15 第1次執行 第二次生成器yield返回值爲 15.0 第三次調用send 第2次接收的term值爲: 30 第2次執行 第三次生成器yield返回值爲 22.5 第四次調用send 第3次接收的term值爲: 10 第3次執行 第四次生成器yield返回值爲 18.333333333333332 |
計算移動平均值 預激協程 |
def init(func): def inner(*args, **kwargs): g = func(*args, **kwargs) next(g) return g return inner @init def averager(): total = 0.0 count = 0 average = None while True: print("第%d次執行" % count) term = yield average total += term count += 1 average = total / count print('第%d次接收的term值爲:' % count) print(term) g_avg = averager() print('\n', '開始') print('第一次調用send') print('第一次生成器yield返回值爲', g_avg.send(15)) print('\n') print('第二次調用send') print('第二次生成器yield返回值爲', g_avg.send(30)) print('\n') print('第三次調用send') print('第三次生成器yield返回值爲', g_avg.send(10)) |
第0次執行 開始 第一次調用send 第1次接收的term值爲: 15 第1次執行 第一次生成器yield返回值爲 15.0 第二次調用send 第2次接收的term值爲: 30 第2次執行 第二次生成器yield返回值爲 22.5 第三次調用send 第3次接收的term值爲: 10 第3次執行 第三次生成器yield返回值爲 18.333333333333332 |
yield from | def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2())) |
['A', 'B', 0, 1, 2] ['A', 'B', 0, 1, 2] |
列表推導式1 | # 30以內所有能被3整除的數 multiples = [i for i in range(30) if i % 3 is 0] print(multiples) |
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27] |
生成器表達式1 | # 生成器表達式 multiples1 = (i for i in range(30) if i % 3 is 0) print(multiples1) print(next(multiples1)) print(multiples1.__next__()) print(next(multiples1)) |
<generator object <genexpr> at 0x0000011DA10FF8E0> 0 3 6 |
列表推導式2 又稱列表解析 缺點:內存佔用大 機器容易卡死 |
multiples = [i for i in range(30) if i % 3 is 0] def squared(x): return x ** 2 # 30以內所有能被3整除的數的平方 multiples2 = [squared(i) for i in range(30) if i % 3 is 0] print(multiples2) |
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729] |
生成器表達式2 優點:幾乎不佔內存 |
multiples3 = (squared(i) for i in range(30) if i % 3 is 0) print(multiples3) print(next(multiples3)) print(multiples3.__next__()) print(next(multiples3)) |
<generator object <genexpr> at 0x000002388D6BF990> 0 9 36 |
列表推導式3 | # 嵌套列表中查詢 兩個‘e’的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] eenames = [name for lst in names for name in lst if name.count('e') >= 2] print(eenames) |
['Jefferson', 'Wesley', 'Steven', 'Jennifer'] |
生成器表達式3 | eenames1 = (name for lst in names for name in lst if name.count('e') >= 2) print(eenames1) print(next(eenames1)) print(eenames1.__next__()) print(next(eenames1)) |
<generator object <genexpr> at 0x0000024A95F9F9E8> Jefferson Wesley Steven |
python內置函數sum | # 使用迭代器協議訪問對象的函數sum ret1 = sum(x ** 2 for x in range(4)) print(ret1) |
14 |
字典推導式1 | # 將字典的Key和Value對調 dic1 = {'a': 1, 'b': 2, } dic1_frequency = {dic1[k]: k for k in dic1} print(dic1_frequency) |
{1: 'a', 2: 'b'} |
字典推導式2 | # 合併大小寫對應的 value值,將K統一成小寫 dic2 = {'a': 1, 'b': 2, 'A': 7, 'D': 6, } print(list(k for k in dic2.keys())) print(list(l1.lower() for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.lower()) for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.lower(), 0) for k in dic2.keys() for l1 in k)) print(list(l1.upper() for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.upper()) for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.upper(), 0) for k in dic2.keys() for l1 in k)) dic2_sortout = {k.lower(): dic2.get(k.lower(), 0) + dic2.get(k.upper(), 0) for k in dic2.keys()} print(dic2_sortout) |
['a', 'b', 'A', 'D'] ['a', 'b', 'a', 'd'] [1, 2, 1, None] [1, 2, 1, 0] ['A', 'B', 'A', 'D'] [7, None, 7, 6] [7, 0, 7, 6] {'a': 8, 'b': 2, 'd': 6} |
集合推導式 | # 計算列表中每個值的平方且自帶去重 squared = {x ** 2 for x in [1, -2, -1, 3]} print(squared) |
{1, 4, 9} |
拓展1 | def demo(): for i in range(4): yield i g = demo() g1 = (i for i in g) g2 = (i for i in g1) print(list(g1)) print(list(g2)) print('\n') g3 = demo() g4 = (i for i in g3) g5 = (i for i in g4) print(list(g5)) print(list(g4)) print('\n') g6 = demo() g7 = (i for i in g6) g8 = (i for i in list(g7)) print(list(g8)) print('\n') g9 = demo() g10 = (i for i in g9) g11 = (i for i in list(g10)) print(list(g11)) print(list(g10)) print('\n') g12 = demo() g13 = (i for i in g12) print(list(g13)) g14 = (i for i in list(g13)) print(list(g11)) print('\n') |
[0, 1, 2, 3] [] [0, 1, 2, 3] [] [0, 1, 2, 3] [0, 1, 2, 3] [] [0, 1, 2, 3] [] |
拓展2 | def add(n, i): return n+i def test(): for i in range(4): yield i g = test() for n in [1, 10]: g = (add(n, i) for i in g) print(list(g)) |
[20, 21, 22, 23] |
拓展2 | def add(n, i): return n+i def test(): for i in range(4): yield i print('g:') g = test() for n in [1, 10]: g = (add(n, i) for i in g) print(list(g)) print('g1:') g1 = test() for n in [10, 1]: g1 = (add(n, i) for i in g1) print(list(g1)) print('g12:') g10 = test() for n in [1, ]: g11 = (add(n, i) for i in g10) for n in [10, ]: g12 = (add(n, i) for i in g11) print(list(g12)) |
g: [20, 21, 22, 23] g1: [2, 3, 4, 5] g12: [20, 21, 22, 23] |
願有更多的朋友,在網頁筆記結構上分享更邏輯和易讀的形式:
鏈接:暫無
提取碼:暫無