python快速學習系列(7):迭代器
迭代器協議
1.迭代器協議:
·迭代器是一個物件
·迭代器可以被next()函式呼叫,並返回一個值
·迭代器可以被iter()函式呼叫,並返回迭代器自己
·連續被next()呼叫時返回一系列的值
·如果到了迭代的末尾,則丟擲StopIteration異常
·迭代器也可以沒有末尾,只要被next()呼叫,就一定會返回一個值
·python中,next()內建函式呼叫的是物件的__next__()方法
·python中,iter()內建函式呼叫的是__iter__()方法
·一個實現了迭代器協議的物件可以被for語句迴圈迭代直到終止
1)只要一個物件實現了__next__()方法,就可以被next()函式呼叫
class XIterator:
def __next__(self):
return 'hello world'
def main()
x_it = XIterator()
[print(next(x_it)) for i in range(3)]
#結果是列印hello world 3次
2)for語句的內部實現
for element in iterable: #do somthing with element #create an iterator object from that iterable iter_obj = iter(iterable) #相當於從一個可迭代器裡返回一個可迭代物件 #infinite loop while True: try: #get the next item element = next(iter_obj) #do somthing with element 也就是說,我們平時寫for語句都是從這裡開始寫,之前和之後的都是直譯器完成的 except StopIteration: #if StopIteration is raised , break from loop break
說明:
for語句裡用的是iterable(可迭代物件),而非iterator(迭代器)
for語句執行的第一個操作是從哪一個iterable生成一個iterator
for語句的迴圈體其實是靠檢測StopIteration異常來中斷的
要想被for語句迭代需要三個條件:iter(),next(),StopIteration
3)一個標準的迭代器的寫法:有__init__,next,iter,StopIteration
class XIterator: def __init__(self): self.elements = list(range(5)) def __next__(self): if self.elements: return self.elements.pop() else: raise StopIteration def __iter__(self): return self def main() x_it = XIterator() for x in x_it: print(x)
2.Generator
·迭代器很有用,但是實現起來有些繁瑣,沒關係,生成器來幫你
·生成器在保持程式碼簡潔優雅的同時,自動實現了迭代器協議
1)實現生成器的方式一:yeild Expression
def f():
yield 1
yield 2
yield 3
def main():
f_gen = f()
for x in f_gen:
print(x)
關鍵字yield和return的區別:yield是暫停,稍後繼續,並會自動實現StopIteration;而return是直接終止
2)實現生成器方式二:Generator expression
[print(x) for x in (x ** 2 for x in range(5))]
#後面()內的表示式就是生成器表示式,即list comprehension的[]變成()就可
不要小看任何看似微小的區別:
sum([x ** 2 for x in range(1000000)])
sum(x ** 2 for x in range(1000000))
第一行:先生成一個長度為1000000的列表,然後在進行就和–>記憶體爆炸
第二行:其實是一個生成器,只是由於sum本身具有()而省略了(),這裡的操作是聚合,即生成一個求和,生成一個求和(幾乎不佔記憶體)
也就是說,如果list存在的價值僅僅是迭代的話,用generator要好得多
3.為什麼需要生成器
·相比迭代器協議,實現生成器的程式碼量小,可讀性高
·相比在List中操作元素,直接使用生成器能節省大量記憶體
·有時候我們會需要寫出一個無法在記憶體中存放的無線資料流
·可以建立生成器管道(多個生成器鏈式呼叫)
1)用生成器表示全部的斐波那契數列
def fibonacci():
temp = [1,1]
while True:
temp.append(sum(temp))
yield temp.pop(0) #yield是實現生成器的關鍵字
2)通過生成器管道模組化處理資料
def fibonacci():
temp = [1,1]
while True:
temp.append(sum(temp))
yield temp.pop(0)
def dataflow():
for x in fibonacci():
yield x ** 2
if __name__ == '__main__':
for x in dataflow():
print(x)
if x > 10000:
break