一個物件(在Python裡面一切都是物件)只要實現了只要實現了__iter__()方法,那麼這個物件就是可迭代物件
針對第一點可以使用print(isinstance([], Iterable)) 進行校驗,返回True則是可迭代物件。
關於第二點我們可以通過print(hasattr([], "__iter__"))返回True知道內部實現了__iter__方法,但是這裡我們需要注意的是要想被for迴圈遍歷,能夠被內建的iter()函數呼叫並轉化成Iterator物件(如下程式碼所示)
from collections import Iterable
class IterObj:
def __iter__(self):
return self
print(isinstance([], Iterable))
it = IterObj()
print(iter(it))
關於 第四點可以根據如下範例理解
from collections import Iterable, Iterator, Generator
class IterObj:
def __init__(self):
self.a = [3, 5, 7, 11, 13, 17, 19]
def __getitem__(self, i):
return self.a[i]
it = IterObj()
print(isinstance(it, Iterable)) # false
print(hasattr(it, "__iter__")) # false
print(isinstance(iter(it), Iterable)) # true
for i in it:
print(i) # 將列印出3、5、7、11、13、17、19
迭代器物件要求支援迭代器協定的物件,在Python中,支援迭代器協定就是實現物件的__iter__()和next()方法。其中__iter__()方法返回迭代器物件本身;next()方法返回容器的下一個元素,在結尾時引發StopIteration異常。簡單來說:一個物件實現了__iter__()和__next__()方法,那麼它就是一個迭代器物件。
class IterObj:
def __init__(self, n):
self.a = n
self.n = len(self.a)
self.i = 0
def __iter__(self):
return iter(self.a)
def __next__(self):
while self.i < self.n:
v = self.a[self.i]
self.i += 1
return v
else:
self.i = 0
raise StopIteration()
t = IterObj([3, 5, 7, 11, 13, 17, 19])
# 可以通過for遍歷
print([ i for i in t])
# 也可以通過next(因為遍歷到沒有資料時候,丟擲異常所以需要捕捉下)
while True:
try:
print(t.__next__())
except:
break
itertion
: 就是迭代
,一個接一個(one after another),是一個通用的概念,比如一個迴圈遍歷某個陣列。
iterable
: 這個是可迭代物件
,屬於python的名詞,範圍也很廣,可重複迭代,滿足如下其中之一的都是iterable
:
可以for
迴圈: for i in iterable
可以按index
索引的物件,也就是定義了__getitem__
方法,比如list,str
;
定義了__iter__
方法。可以隨意返回。
可以呼叫iter(obj)
的物件,並且返回一個iterator
iterator
: 迭代器物件
,也屬於python的名詞,只能迭代一次。需要滿足如下的迭代器協定
定義了__iter__
方法,但是必須返回自身
定義了next
方法,在python3.x是__next__
。用來返回下一個值,並且當沒有資料了,丟擲StopIteration
可以保持當前的狀態
迭代器優點:
迭代器缺點:
生成器就是一種自定義的迭代器,本質為迭代器,但凡函數內包含yield關鍵字,呼叫函數不會執行函數體程式碼,會得到一個返回值,該返回值就是生成器物件。在廖雪峰教學中解釋為:在Python中,這種一邊迴圈一邊計算的機制,稱為生成器(Generator)
注意: 生成器既是可迭代的也是迭代器
yield
定義生成器函數 (yield
是一個語法糖,內部實現了迭代器協定,同時保持狀態可以掛起)from collections import *
g = (x for x in range(3)) # 0~18的偶數生成器
print(isinstance(g, Iterable)) # true
print(isinstance(g, Iterator)) # true
print(isinstance(g, Generator)) # true
print(hasattr(g, "__iter__")) # true
print(hasattr(g, "__next__")) # true
print(next(g)) # 0
print(next(g)) # 1
print(next(g)) # 2
yield
定義生成器函數def gen():
for i in range(10):
yield i
# 檢索資料,開始執行
a = gen()
print(list(a))
# 呼叫gen()並沒有真實執行函數,而是隻是返回了一個生成器物件
# 執行第一次a.next()時,才真正執行函數,執行到yield一個返回值,然後就會掛起,
# 保持當前的名稱空間等狀態。然後等待下一次的呼叫,從yield的下一行繼續執行。
a = gen()
print(a.__next__())
這裡yield
的作用就相當於return
,這個函數就是順序地返回[0,9]
的之間的自然數,可以通過next()
或使用for
迴圈來遍歷。當程式遇到yield
關鍵字時,這個生成器函數就返回了,直到再次執行了next()
函數,它就會從上次函數返回的執行點繼續執行,即yield
退出時儲存了函數執行的位置、變數等資訊,再次執行時,就從這個yield
退出的地方繼續往下執行。
生成器能做到迭代器能做的所有事,而且因為自動建立了 iter()和 next()方法,生成器顯得特別簡潔,而且生成器也是高效的,使用生成器表示式取代列表解析可以同時節省記憶體。