python中的for、迭代器和生成器的理解

上圖的這些模式,都是以list對象和操作符[]來獲取元素,而索引只是作為參數。這是一種迭代模式。
有沒有一種模式,元素的提取只和下標打交道,而和可迭代對象無關。這樣的一種設計模式,就是迭代器模式
for i in [1, 2, 3, 4]:
print(i)
for c in "python":
print(c)
for k in {"x": 1, "y": 2}:
print(k)
for line in open("a.txt"):
print(line, end="")
這些例子中,字符串、列表、字典、文件都可以使用for循環,這些類型都是可迭代對象(字符串、列表、字典、文件)。
迭代器模式特別適合于以下情形:
1、不關心元素的隨機訪問(不需要干涉遍歷的過程,只需要取出來元素)
2、元素的個數不可提前預測(元素個數未知,不像列表、字典、文件那樣有固定大小,可以提前加載到內存中)。
那是如何實現迭代器的?
1、返回當前『位置』的元素,當前位置是可迭代對象的起始位置
2、將『位置』向后遞增
3、如果到達可迭代對象的末尾,即沒有元素可以提取,則拋出StopIteration異常
Python的iter函數和next函數的內部實現:
def iter(obj):
return obj.__iter__()
#Python 2.X
def next(obj):
return obj.next()
#Python 3.X
def next(obj):
return obj.__next__()
iter()和next()方法:
iter()參數是可迭代對象,返回值返回一個迭代器。
next()參數是迭代器,返回值是迭代器中的下一個元素,如果沒有下一個元素,則拋出StopIteration異常。
1)可迭代對象包含迭代器。
2)如果一個對象擁有__iter__方法,其是可迭代對象;如果一個對象擁有next方法,其是迭代器。
3)定義可迭代對象,必須實現__iter__方法;定義迭代器,必須實現__iter__和next方法。
可迭代對象、迭代器、生成器之間的關系:

結論3與結論2是不是有一點矛盾?既然一個對象擁有了next方法就是迭代器,那為什么迭代器必須同時實現兩方法呢?
因為結論1,迭代器也是可迭代對象,因此迭代器必須也實現__iter__方法。
而一個生成器是一個迭代器。
可迭代對象是指:只要具有__iter__或__getitem__的object就是可迭代對象。
而同時具有__iter__和__next__方法的的對象為Iterator迭代器。
而判斷一個對象是可迭代對象或者迭代器的方法:
1、利用dir(類型)或者hasattr(類型)去檢查是否含有__iter__、__getitem__和__next__這些方法,來判斷是一個可迭代對象還是迭代器。
2、isinstance(對象,Iterable),isinstance(對象,Iterator)
例如:
list對象有__iter__以及__getitem__但沒有__next__,
所以是list列表是可迭代對象Iterable,但不是迭代器Iterator。
但是,可以通過調用 iter(list)函數,(其實就是call list.__iter__()),
這樣會返回一個同時帶有__iter__和__next__的新的對象,這個返回值就是一個迭代器Iterator了。

而for循環中 的對象,不需要一定是 迭代器Iterator,只要是可迭代對象就行了。
yield作為及物動詞表示產出;作為不及物動詞,它表示讓步或撤回。python在生成器函數中都體現了這個功能。

1、yield只能出現在function里,而調用帶有yield功能的函數會回返回一個Generator生成器對象。
2、Generatoro對象是一個Iterator,帶有__iter__和__next__屬性。
3、第一次調用next(generator)執行內容等價于將原功能執行到第一次出現yield處,返回yield后的值,并“暫停”執行。
4、第二次之后每次調用next(generator)都會不斷從上次「暫停」處繼續執行,直到功能全部執行完畢并執行StopIteration。因為yield沒有將原功能從調用堆棧中移除,故能暫停并重新回到上次暫停處繼續執行。這邏輯也是yield和return最核心不同之處,return會直接將原函數從調用堆棧中移除,終止函數,無論return后面是還是還有其他程序代碼。
5、yeild除了可傳出值外,也可以接受由外部輸入的值,利用generator.send()可以傳出和傳入值。此設計,讓Generator對象可和外部進行雙向溝通,可以傳出,也可以設定值。
6、關于Generator生成器對象創建的兩種語法:一是在function內加入yield”,二是形如x = (i for i in y)的方式。
其實大家常用的產生列表的其中一種寫法x = [i for i in range(10)]就是創建一個Generator對象的變形。
迭代器的實現類似于類,其中有兩個方法,一個是__iter__,一個是__next__
class iteror:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self): #參數是一個可迭代對象
return self #返回值是一個迭代器
def __next__(self): #參數是一個迭代器
if self.i < self.n:
i = self.i
self.i += 1
return i #返回下一個元素
else:
raise StopIteration() #沒有下一個元素,拋出異常
參考文章:https://medium.com/citycoddee/python%E9%80%B2%E9%9A%8E%E6%8A%80%E5%B7%A7-6-%E8%BF%AD%E4%BB%A3%E9%82%A3%E4%BB%B6%E5%B0%8F%E4%BA%8B-%E6%B7%B1%E5%85%A5%E4%BA%86%E8%A7%A3-iteration-iterable-iterator-iter-getitem-next-fac5b4542cf4

浙公網安備 33010602011771號