徹底理解Python迭代器
如何理解迭代物件迭代器以及迭代協議:
Iterable Iterator
1、可迭代物件和迭代器
可迭代的物件有個 __iter__ 方法,每次都例項化一個新的迭代器;而迭代器要實現 __next__ 方法,返回單個元素,此外還要實現 __iter__ 方法,返回迭代器本身
可迭代的物件一定不能是自身的迭代器。也就是說,可迭代的物件必須實現
__iter__ 方法,但不能實現 __next__ 方法
2、迭代器:
迭代器是這樣的物件:實現了無引數的 __next__ 方法,返回序列中的下一個元素;如果沒有元素了,那麼丟擲 StopIteration 異常。 Python 中的迭代器還實現了
3、序列可以迭代原因
iter 函式:直譯器需要迭代物件X時,會自動呼叫iter(X)
4、內建iter函式作用
1、檢查物件是否實現了__iter__方法,如果實現就呼叫,獲取一個迭代器。
2、如果沒有實現__iter__,但是有__getitem__方法,Python會建立一個迭代器,嘗試按順序從索引0開始獲取元素。
3、如果嘗試失敗丟擲TypeError異常
4、理解迭代協議
Python 迭代協議要求一個 __iter__() 方法返回一個特殊的迭代器,這個迭代器實現了 __next__() 方法,並通過StopIteration
Eg: 如下程式碼,按照迭代協議描述:
# -*- coding:utf -*-
import re
import reprlib
RE_WORD= re.compile('\w+')
class Sentence:
def__init__(self, text):
self.text= text
self.words= RE_WORD.findall(text)
def__repr__(self):
return 'Sentence(%s)' %reprlib.repr(self.text)
def__iter__(self):
return SentenceIterator(self.words)
class SentenceIterator:
def__init__(self, words):
self.words= words
self.index= 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index+= 1
return word
def__iter__(self):
return self
if __name__ == '__main__':
s = Sentence('helloworld')
it = iter(s)
print(it)
print(next(it))
print(next(it))
結果:
<__main__.SentenceIteratorobject at 0x03561F30>
hello
World
符合可迭代物件和迭代器的描述情況。
如果我們不按照這種協議的說明:__iter__ 函式不返回一個迭代器,使用別的函式返回迭代器情況會是什麼。修改程式碼如下,並執行列印:
# -*- coding:utf -*-
import re
import reprlib
RE_WORD= re.compile('\w+')
class Sentence:
def__init__(self, text):
self.text= text
self.words= RE_WORD.findall(text)
def__repr__(self):
return 'Sentence(%s)' %reprlib.repr(self.text)
def__iter__(self):
return iter(self.words)
defshow_word(self):
return SentenceIterator(self.words)
class SentenceIterator:
def__init__(self, words):
self.words= words
self.index= 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index+= 1
return word
def__iter__(self):
return self
if __name__ == '__main__':
s = Sentence('helloworld')
print(s.show_word())
print(next(s.show_word()))
forword in s.show_word():
print(word)
執行結果:
<__main__.SentenceIteratorobject at 0x03271250>
hello
hello
world
接著執行如下:
if __name__ == '__main__':
s = Sentence('helloworld')
it = iter(s)
print(it)
print(next(it))
print(next(it))
執行結果:
<list_iteratorobject at 0x02B21FB0>
hello
world
因為 __iter__ 函式返回值是個list 型別,所以使用iter()函式依舊可以生成一個list_iterator。原始資料可迭代,使用iter()函式可生成一個迭代器
如果原始資料不可迭代,呼叫iter就會報錯:
>>> s = 14
>>> s
14
>>>iter(14)
Traceback (mostrecent call last):
File "<pyshell#51>", line 1,in <module>
iter(14)
TypeError: 'int'object is not iterable
以上兩種方式是為了理解迭代物件和迭代器,實時上這種寫法過於繁瑣,使用生成器來實現迭代器:
# -*- coding:utf -*-
import re
import reprlib
RE_WORD= re.compile('\w+')
class Sentence:
def__init__(self, text):
self.text= text
self.words= RE_WORD.findall(text)
def__repr__(self):
return 'Sentence(%s)' %reprlib.repr(self.text)
def__iter__(self):
for i in self.words:
yield i
if __name__ == '__main__':
s = Sentence('helloworld')
it = iter(s)
print(it)
print(next(it))
print(next(it))
輸出結果:
<generator objectSentence.__iter__ at 0x0355DF60>
hello
world
使用生成器很大減少了繁瑣的自己實現一個迭代器並且實現 __next__方法。
當然生成器除了使用: yield關鍵字以外還可以使用生成器表示式,類似於列表推導式。
# -*- coding:utf-8 -*-
def gen_():
print('start')
yield'a'
print('continue')
yield'b'
print('end.')
res1 =[x*3 for x in gen_()]
print(res1)
res2 =(x*3 for x in gen_())
print(res2)
輸出結果:
start
continue
end.
['aaa', 'bbb']
<generator object<genexpr> at 0x02B36540>
列表推導式直接打印出來了所有的結果,而生成器表示式並沒有,生成器表示式可以使用next()函式來輸出結果。