指能夠被內置函數`next`調用並不斷返回下一個值,直到最後拋出`StopIteration`錯誤表示無法繼續返回下一個值的對象稱為迭代器(`Iterator`) ...
指能夠被內置函數
next
調用並不斷返回下一個值,直到最後拋出StopIteration
錯誤表示無法繼續返回下一個值的對象稱為迭代器(Iterator
)
其實以上的說法只是俠義上的迭代器的定義,在python中,迭代器還需要實現可迭代介面(Iterable
),可迭代介面需要返回的是一個迭代器對象,這樣迭代器就能夠被for
語句進行迭代。
迭代器對象初步認知
在python
中,沒有內置迭代器類型的對象,但是可以通過內置函數iter
將str
、tuple
、list
、dict
、set
等類型轉換成一個迭代器對象。
>>> s = 'abc'
>>> next(s)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
next(s)
TypeError: 'str' object is not an iterator
# 以上報錯信息可以看出`str`不是迭代器
>>> it_s = iter(s)
>>> next(it_s)
'a'
>>> next(it_s)
'b'
>>> next(it_s)
'c'
>>> next(it_s)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
next(it_s)
StopIteration
# 以上報錯信息可以看出`iter(str)`是迭代器
通過不斷的調用next(iterator)
方法來獲取下一個值,這樣其實不怎麼方便,python
提供了更為簡潔的方法,即for
迴圈。for
迴圈每執行一次即相當於調用了一次next(iterator)
方法,直到捕獲到StopIteration
異常退出迴圈。
>>> it_s = iter(s)
>>> for c in it_s:
print(c)
a
b
c
# 以上的例子是使用for迴圈遍歷迭代器
模塊collections
中的類型Iterator
就是迭代器的抽象基類,所有的迭代器都是Iterator
的實例。即如果一個對象是Iterator
的實例,則說明此對象是迭代器。
from collections import Iterator
>>> isinstance(s,Iterator)
False
>>> isinstance(it_s,Iterator)
True
# 以上信息證實了`str`不是迭代器,而`iter(str)`是迭代器
如何自己實現一個迭代器
根據python
鴨子類型的特性,我們自定義的類型中,只要實現了__next()__
方法,該方法在每次被調用時不斷返回下一個值,直到無法繼續返回下一個值時拋出StopIteration
異常即可(next(iterator
)實際上調用的是iterator內部的__next()__
方法)。
定義自己的迭代器
>>> class MyIter():
def __init__(self,max_value):
self.current_value = 0
self.max_value = max_value
def __next__(self):
if self.current_value < self.max_value:
result = self.current_value
self.current_value += 1
return result
else:
raise StopIteration
驗證next
方法是否不停返回下一個值
>>> my_iter = MyIter(3)
>>> next(my_iter)
0
>>> next(my_iter)
1
>>> next(my_iter)
2
>>> next(my_iter)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
next(my_iter)
StopIteration
驗證對象是否可以用於for
迴圈
>>> my_iter = MyIter(3)
>>> for i in my_iter:
print(i)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
for i in my_iter:
TypeError: 'MyIter' object is not iterable
驗證對象是否是Iterator
實例
>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
False
從上面的驗證可以看出僅僅實現__next()__
方法的對象還不是迭代器,真正的迭代器還需要實現一個可迭代介面Iterable
。
Iterator
和Iterable
的關係
在模塊collections
中的類型Iterator
就是迭代器的抽象基類,其實它裡面還定義了類型Iterable
,它是可迭代對象的抽象基類。先分別通過help
命令查看他們的定義:
>>> from collections import Iterator, Iterable
>>> help(Iterator)
Help on class Iterator in module collections.abc:
class Iterator(Iterable)
| Method resolution order:
| Iterator
| Iterable
| builtins.object
|
| Methods defined here:
|
| __iter__(self)
|
| __next__(self)
| Return the next item from the iterator. When exhausted, raise StopIteration
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(C) from abc.ABCMeta
| Abstract classes can override this to customize issubclass().
|
| This is invoked early on by abc.ABCMeta.__subclasscheck__().
| It should return True, False or NotImplemented. If it returns
| NotImplemented, the normal algorithm is used. Otherwise, it
| overrides the normal algorithm (and the outcome is cached).
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset({'__next__'})
>>> help(Iterable)
Help on class Iterable in module collections.abc:
class Iterable(builtins.object)
| Methods defined here:
|
| __iter__(self)
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(C) from abc.ABCMeta
| Abstract classes can override this to customize issubclass().
|
| This is invoked early on by abc.ABCMeta.__subclasscheck__().
| It should return True, False or NotImplemented. If it returns
| NotImplemented, the normal algorithm is used. Otherwise, it
| overrides the normal algorithm (and the outcome is cached).
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset({'__iter__'})
通過上面的代碼,可以清楚的看出迭代器類型Iterator
繼承自可迭代類型Iterable
,可迭代Iterable
繼承自object
基類,迭代器Iterator
類型包含__iter()__
和__next()__
方法,而可迭代類型Iteratble
僅僅包含__iter__()
。可迭代對象,通過__iter()__
返回一個迭代器對象,迭代器對象的__next()__
方法則實際用於被迴圈。
完善自己實現一個迭代器
我們現在再將MyIter
類型實現可迭代介面Iterable
,即實現__iter__()
方法。
>>> class MyIter():
def __init__(self,max_value):
self.current_value = 0
self.max_value = max_value
def __iter__(self):
return self
def __next__(self):
if self.current_value < self.max_value:
result = self.current_value
self.current_value += 1
return result
else:
raise StopIteration
驗證對象是否可以用於for
迴圈
>>> my_iter = MyIter(3)
>>> for i in my_iter:
print(i)
0
1
2
驗證對象是否是Iterator
實例
>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
True
總結
- 凡是可作用於
for
語句迴圈的對象都是Iterable
可迭代類型。 - 凡是可作用於
next()
函數的對象都是Iterator
迭代器類型。 str
、tuple
、list
、dict
、set
等類型是Iterable
可迭代類型,但不是Iterator
迭代器;通過Iterable
可迭代類型的__iter()__
方法可以獲得一個Iterator
迭代器對象,從而使得它們可以被for語句迴圈。Python
的for
迴圈本質上就是通過調用Iterable
可迭代對象的__iter()__
方法獲得一個Iterator
迭代器對象,然後不斷調用Iterator
迭代器對象__next()__
方法實現的。