python 迭代器、生成器、yield、iter
生活随笔
收集整理的這篇文章主要介紹了
python 迭代器、生成器、yield、iter
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. 迭代器
- 2. 生成器
- 3. 標準庫
- 3.1 過濾
- 3.2 映射
- 3.3 合并
- 3.4 排列組合
- 3.5 重新排列
- 4. yield from
- 5. 可迭代的歸約函數
- 6. iter 還可以傳入2個參數
- 7. 生成器當成協程
learn from 《流暢的python》
1. 迭代器
- 所有生成器都是迭代器,因為生成器完全實現了迭代器接口
- 序列可以迭代的原因:iter函數,解釋器需要迭代對象 x 時,會自動調用 iter(x)
- 內置的 iter:先檢查是否實現了 __iter__,不然,檢查是否實現 __getitem__并創建迭代器
標準的迭代器接口有兩個方法
- __next__ 返回下一個可用的元素,如果沒有元素了,拋出 StopIteration 異常
- __iter__ 返回 self,以便在應該使用可迭代對象的地方使用迭代器,例如 在 for 循環中
不要在可迭代對象的類中實現迭代器,一舉兩得?錯誤,大佬教我不要這么做!
- 為了支持多種遍歷,需要獲取獨立的多個迭代器,每次調用 iter() 都創建獨立的迭代器對象
可迭代的對象 一定不能 是 自身的迭代器
也就是說,可迭代的對象 必須實現 __iter__ 方法,但不能實現 __next__ 方法
2. 生成器
只要 Python 函數的定義體中有 yield 關鍵字,該函數就是生成器函數
調用生成器函數時,會返回一個生成器對象
惰性獲取匹配項 re.finditer ,可以節省內存和無效工作
生成器表達式可以理解為列表推導的惰性版本,按需 惰性生成元素
def genAB():print("start")yield 'A'print("continue")yield 'B'print("end")ans1 = [x*2 for x in genAB()] # 循環迭代列表推導生成的 ans1 列表 # 輸出以下內容 # start # continue # endfor x in ans1:print(x) # 輸出 # AA # BBans2 = (x*2 for x in genAB()) # 生成器表達式會產出生成器,ans2 是一個生成器對象 # 無輸出for x in ans2: # 調用時,才真正執行 genAB 函數產出數值print(x) # 輸出 # start # AA # continue # BB # end3. 標準庫
import itertools gen = itertools.count(5, 0.5) print(next(gen)) print(next(gen)) print(next(gen)) # 5 # 5.5 # 6.0- list(count()) 會生成無窮的序列,內存會爆炸
- takewhile 不滿足條件時退出
3.1 過濾
def vowel(c):return c.lower() in "aeiou"print(list(filter(vowel, "Abcdea"))) # ['A', 'e', 'a'] print(list(itertools.filterfalse(vowel, "Abcdea"))) # ['b', 'c', 'd'] print(list(itertools.dropwhile(vowel, "Aardvark"))) # ['r', 'd', 'v', 'a', 'r', 'k'] 遇到不滿足的即停止檢測 print(list(itertools.takewhile(vowel, "Aardvark"))) # ['A', 'a'] 遇到不滿足的即停止檢測 print(list(itertools.compress('Aardvark', (1, 0, 1, 1, 0, 1)))) # 產出后者是真值的前者元素 ['A', 'r', 'd', 'a'] print(list(itertools.islice('Aardvark', 4))) # ['A', 'a', 'r', 'd'] 前 4 個元素 print(list(itertools.islice('Aardvark', 4, 7))) # ['v', 'a', 'r'] [4,7) 的元素 print(list(itertools.islice('Aardvark', 1, 7, 2))) # ['a', 'd', 'a'] [1,7) 每 2 個 取一個3.2 映射
sample = [9, 5, 4, 6, 8, 9] print(list(itertools.accumulate(sample))) # [9, 14, 18, 24, 32, 41] 累加求和,前綴和 print(list(itertools.accumulate(sample, min))) # [9, 5, 4, 4, 4, 4] 累積的最小值 print(list(itertools.accumulate(sample, max))) # [9, 9, 9, 9, 9, 9] print(list(itertools.accumulate(sample, operator.mul))) # [9, 45, 180, 1080, 8640, 77760] 前綴乘積 print(list(itertools.accumulate(range(1, 11), operator.mul))) # [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] print(list(enumerate("abc", start=2))) # [(2, 'a'), (3, 'b'), (4, 'c')] print(list(map(operator.mul, range(11), range(1, 11)))) # x*(x+1) 對應相乘,元素少的結束即停止 print(list(map(lambda a, b: (a, b), range(11), [2, 4, 8]))) # [(0, 2), (1, 4), (2, 8)] 等效于 zip 函數 print(list(itertools.starmap(operator.mul, enumerate('abc', 1)))) # ['a', 'bb', 'ccc'] sample = [2, 3, 4, 5] print(list(itertools.starmap(lambda a, b: b / a, enumerate(itertools.accumulate(sample), 1)))) # 求累積 均值 [2.0, 2.5, 3.0, 3.5]3.3 合并
print(list(itertools.chain("ABC", range(5)))) # ['A', 'B', 'C', 0, 1, 2, 3, 4] , 可傳入多個可迭代對象 print(list(itertools.chain(enumerate('ABC')))) # [(0, 'A'), (1, 'B'), (2, 'C')] 傳入一個參數,沒啥用 print(list(itertools.chain.from_iterable(enumerate('ABC')))) # 只接收一個參數,且對象是可迭代的 # [0, 'A', 1, 'B', 2, 'C'] print(list(zip('ABC', range(5)))) # [('A', 0), ('B', 1), ('C', 2)] 短的先結束 print(list(zip('ABC', range(5), [10, 20, 30, 40]))) # [('A', 0, 10), ('B', 1, 20), ('C', 2, 30)] 課輸入多個參數 print(list(itertools.zip_longest('ABC', range(5)))) # [('A', 0), ('B', 1), ('C', 2), (None, 3), (None, 4)], 以最長的為結束 print(list(itertools.zip_longest('ABC', range(5), fillvalue='?'))) # [('A', 0), ('B', 1), ('C', 2), ('?', 3), ('?', 4)] 填充默認值 # 笛卡爾積,惰性生成 print(list(itertools.product('ABC', range(2)))) # [('A', 0), ('A', 1), ('B', 0), ('B', 1), ('C', 0), ('C', 1)] print(list(itertools.product('ABC'))) # [('A',), ('B',), ('C',)] 傳入一個參數,得到只有一個元素的元組,沒啥用 print(list(itertools.product('ABC', repeat=2))) # [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')] # 相當于兩重循環 print(list(itertools.product(range(2), repeat=3))) # [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)] # 3 重循環 rows = itertools.product('AB', range(2), repeat=2) for row in rows: print(row) # ('A', 0, 'A', 0) # ('A', 0, 'A', 1) # ('A', 0, 'B', 0) # ('A', 0, 'B', 1) # ('A', 1, 'A', 0) # ('A', 1, 'A', 1) # ('A', 1, 'B', 0) # ('A', 1, 'B', 1) # ('B', 0, 'A', 0) # ('B', 0, 'A', 1) # ('B', 0, 'B', 0) # ('B', 0, 'B', 1) # ('B', 1, 'A', 0) # ('B', 1, 'A', 1) # ('B', 1, 'B', 0) # ('B', 1, 'B', 1) print("-----") for a in "AB":for b in range(2):for c in "AB":for d in range(2):print((a, b, c, d)) # ('A', 0, 'A', 0) # ('A', 0, 'A', 1) # ('A', 0, 'B', 0) # ('A', 0, 'B', 1) # ('A', 1, 'A', 0) # ('A', 1, 'A', 1) # ('A', 1, 'B', 0) # ('A', 1, 'B', 1) # ('B', 0, 'A', 0) # ('B', 0, 'A', 1) # ('B', 0, 'B', 0) # ('B', 0, 'B', 1) # ('B', 1, 'A', 0) # ('B', 1, 'A', 1) # ('B', 1, 'B', 0) # ('B', 1, 'B', 1) 跟上面結果一致 ct = itertools.count() print(next(ct), next(ct), next(ct), next(ct), next(ct)) # 0 1 2 3 4 print(list(itertools.islice(itertools.count(1, .3), 3))) # [1, 1.3, 1.6] cy = itertools.cycle('ABC') print(next(cy), next(cy), next(cy), next(cy)) # A B C A, 產生元素的副本,不斷重復 print(list(itertools.islice(cy, 7))) # ['B', 'C', 'A', 'B', 'C', 'A', 'B'] rp = itertools.repeat(7) print(list(itertools.islice(rp, 10))) # [7, 7, 7, 7, 7, 7, 7, 7, 7, 7] print(list(itertools.repeat(8, 4))) # [8, 8, 8, 8] print(list(map(operator.mul, range(11), itertools.repeat(5)))) # [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50] 0-10 分別乘以53.4 排列組合
print(list(itertools.combinations("ABC", 2))) # [('A', 'B'), ('A', 'C'), ('B', 'C')] # 組合:從中取出2個的方案數,無序要求 C32 print(list(itertools.combinations_with_replacement("ABC", 2))) # [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')] # 組合:無序,可重復 print(list(itertools.permutations("ABC", 2))) # [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')] # 排列:有順序要求 print(list(itertools.product("ABC", repeat=2))) # 的笛卡兒積 # [('A', 'A'), ('A', 'B'), ('A', 'C'), # ('B', 'A'), ('B', 'B'), ('B', 'C'), # ('C', 'A'), ('C', 'B'), ('C', 'C')]3.5 重新排列
print(list(itertools.groupby("LLLLAAGGG"))) # [('L', <itertools._grouper object at 0x000001A6D638C460>), # ('A', <itertools._grouper object at 0x000001A6D6538E80>), # ('G', <itertools._grouper object at 0x000001A6D8F7EA00>)] for char, group in itertools.groupby("LLLLAAGGG"):print(char, "->", list(group))# L -> ['L', 'L', 'L', 'L'] # A -> ['A', 'A'] # G -> ['G', 'G', 'G']for char, group in itertools.groupby("ALLLLAAGGG"):print(char, "->", list(group)) # A -> ['A'] # 沒有相鄰的A # L -> ['L', 'L', 'L', 'L'] # A -> ['A', 'A'] # G -> ['G', 'G', 'G']animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear', 'bat', 'dolphin', 'shark', 'lion'] animals.sort(key=len) # 按長度排序 print(animals) # ['rat', 'bat', 'duck', 'bear', 'lion', 'eagle', 'shark', 'giraffe', 'dolphin'] for length, group in itertools.groupby(animals, len):print(length, "->", list(group)) # 3 -> ['rat', 'bat'] # 4 -> ['duck', 'bear', 'lion'] # 5 -> ['eagle', 'shark'] # 7 -> ['giraffe', 'dolphin'] for length, group in itertools.groupby(reversed(animals), len):print(length, "->", list(group)) # 7 -> ['dolphin', 'giraffe'] # 5 -> ['shark', 'eagle'] # 4 -> ['lion', 'bear', 'duck'] # 3 -> ['bat', 'rat'] abc = ["apple", "bear", "animals", "bull", "lakers"] abc.sort() for char, group in itertools.groupby(abc, lambda x: x[0]):print(char, "->", list(group)) # 按首字母分組 # a -> ['animals', 'apple'] # b -> ['bear', 'bull'] # l -> ['lakers'] # itertools.tee 函數產出多個生成器,每個生成器都 可以產出輸入的各個元素 # 默認2個,后面可加參數 n, 輸出多個 print(list(itertools.tee("ABC"))) # [<itertools._tee object at 0x000001D4AEEE8AC0>, # <itertools._tee object at 0x000001D4AEEE8A80>] g1, g2 = itertools.tee("ABC") print(next(g1)) # A print(list(g1)) # ['B', 'C'] print(next(g2), next(g2)) # A B print(list(g2)) # ['C'] print(list(zip(*itertools.tee('ABC')))) # [('A', 'A'), ('B', 'B'), ('C', 'C')]4. yield from
yield from 語句的作用就是把不同的生成器結合在一起使用
def chain(*iterables):for it in iterables:for i in it:yield i s = "ABC" t = tuple(range(3)) print(list(chain(s, t))) # ['A', 'B', 'C', 0, 1, 2]def chain1(*iterables):for it in iterables:yield from it# 完全代替了內層的 for 循環 print(list(chain1(s, t))) # ['A', 'B', 'C', 0, 1, 2]5. 可迭代的歸約函數
- any, all 可以短路,一旦確定結果,就停止迭代
- 也可以這樣調用 max(arg1, arg2, ..., [key=?])
- sorted 操作完成后返回排序后的 列表。它可以處理任意的可迭代對象
6. iter 還可以傳入2個參數
- 當遇到第二個參數時停止迭代
這段代碼逐行讀取文件,直到遇到空行或者到達文件末尾為止
with open('mydata.txt') as fp:for line in iter(fp.readline, '\n'):process_line(line)7. 生成器當成協程
- .send() 方法,后面會學到
- 與 .__next__() 方法一樣,.send() 方法致使生成器前進到下一個 yield 語句
- .send() 方法還允許使用生成器的客戶 把 數據 發給 自己,即不管傳給 .send() 方法什么參數,那個參數都會 成為生成器 函數定義體中對應的 yield 表達式的值
總結
以上是生活随笔為你收集整理的python 迭代器、生成器、yield、iter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 1805. 字符串中不
- 下一篇: LeetCode 1877. 数组中最大