在Python中,有這兩個概念容易讓人混淆。第一個是可迭代對象(Iterable),第二個是迭代器(Iterator),第三個是生成器(Generator),這裏暫且不談生成器。python
列表、元組、字符串、字典等都是可迭代對象,可使用for循環遍歷出全部元素的均可以稱爲可迭代對象(Iterable)。在Python的內置數據結構中定義了Iterable這個類,在collections.abc模塊中,咱們能夠用這個來檢測是否爲可迭代對象數據結構
>>> from collections import Iterable >>> a = [1,2,3] >>> isinstance(a, Iterable) >>> True >>> b = 'abcd' >>> isinstance(b, Iterable) >>> True
這些數據結構之因此能稱之爲Iterable,是由於其內部實現了__iter__()方法,從而可迭代。當咱們使用for循環時,解釋器會調用內置的iter()函數,調用前首先會檢查對象是否實現了__iter__()方法,若是有就調用它獲取一個迭代器(接下來會講)。加入沒有__iter__()方法,可是實現了__getitem__()方法,解釋器會建立一個迭代器而且按順序獲取元素。若是這兩個方法都沒有找到,就會拋出TypeError異常。下面咱們自定義對象,分別實現這兩個方法(getitem(), iter())dom
class MyObj: def __init__(self, iterable): self._iterable = list(iterable) def __getitem__(self, item): return self._iterable[item] obj = MyObj([1,2,3]) for i in obj: print(i)
如上所示,這裏沒有實現__iter__方法,只實現了__getitem__方法,也使得Myobj稱爲可迭代對象。
下面咱們實現__iter__方法,這裏使用了yield語法用來產出值(這裏須要生成器的知識)ssh
class MyObj: def __init__(self, iterable): self._iterable = list(iterable) def __iter__(self): index = 0 while True: try: yield self._iterable[index] except IndexError: break index += 1 obj = MyObj([1,2,3]) for i in obj: print(i)
這裏一樣讓對象稱爲可迭代對象。函數
迭代器是一個能夠記住遍歷的位置的對象。
迭代器對象從集合的第一個元素開始訪問,直到全部的元素被訪問完結束。迭代器只能往前不會後退。code
如上圖所示,迭代器(Iterator)繼承可迭代(Iterable),迭代器必須實現__iter__方法和__next__方法。其中__next__方法用於產出下一個元素。
由繼承圖可見,迭代器必定是可迭代對象,可迭代對象不必定是迭代器
迭代器有兩個基本的方法:iter() 和 next()。
咱們使用iter(iterable)便可把可迭代對象轉換成迭代器
使用next(iterator)來獲取迭代器的下一個值orm
>>> a = [3,4,5] >>> a >>> [3, 4, 5] >>> iter(a) >>> <list_iterator object at 0x10b130ba8> >>> iterator = iter(a) >>> next(iterator) >>> 3 >>> next(iterator) >>> 4 >>> next(iterator) >>> 5 >>> next(iterator) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration
如上所示,由於對象實現了__next__方法,咱們能夠經過next(iterator)來獲取迭代器的下一個值,直到沒有值了,拋出StopIteration異常結束。對象
迭代器Iterator是一個抽象基類,它定義在_collections_abc.py中
Iterator源碼
以下blog
class Iterator(Iterable): __slots__ = () @abstractmethod def __next__(self): 'Return the next item from the iterator. When exhausted, raise StopIteration' raise StopIteration def __iter__(self): return self @classmethod def __subclasshook__(cls, C): if cls is Iterator: return _check_methods(C, '__iter__', '__next__') return NotImplemented
能夠看到,它實現了__subclasshook__方法,即不用顯式繼承Iterator,只須要實現__iter__和__next__方法便可稱爲Iterator的虛擬子類。這裏凸現了Python的鴨子類型,實現特定的「協議」便可擁有某種行爲。
另外,它本身也定義了__iter__方法,當咱們使用iter(Iterator)時直接返回本身,不作任何處理。繼承
官方文檔中給出了說明:
iter(iterable) -> iterator iter(callable, sentinel) -> iterator Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.
第一個用法:iter(iterable) -> iterator (把可迭代對象轉換爲迭代器)
第二個用法:iter(callable, sentinel) -> iterator (第一個參數:任何可調用對象,能夠是函數,第二個是標記值,當可調用對象返回這個值時,迭代器拋出StopIteration異常,而不產出標記值)
>>> from random import choice >>> values = [1,2,3,4,5,6,7] >>> def test_iter(): >>> return choice(values) >>> it = iter(test_iter, 2) >>> it >>> <callable_iterator object at 0x10b130b00> >>> for i in it: >>> print(i) >>> 7 >>> 1 >>> 7 >>> 3 >>> 1
上面代碼的流程:test_iter函數從values列表中隨機挑選一個值並返回,調用iter(callable, sentinel)函數,把sentinel標記值設置爲2,返回一個callable_iterator實例,遍歷這個特殊的迭代器,若是函數返回標記值2,直接拋出異常退出程序。這就是iter函數的不爲人知的另外一個用法。