同時,Iterator自己也是壹種Iterable,所以也需要實現Iterable的接口,也就是__iter__,這樣在for當中兩者都可以使用。Iterator的__iter__只需要返回自己就行了。這樣,下面的代碼就可以工作:
for i in my_list:
...
for i in iter(mylist):
...
for i in (v for v in mylist if v is not None):
...
Python中許多方法直接返回iterator,比如itertools裏面的izip等方法,如果Iterator自己不是Iterable的話,就很不方便,需要先返回壹個Iterable對象,再讓Iterable返回Iterator。生成器表達式也是壹個iterator,顯然對於生成器表達式直接使用for是非常重要的。
那麽為什麽不只保留Iterator的接口而還需要設計Iterable呢?許多對象比如list、dict,是可以重復遍歷的,甚至可以同時並發地進行遍歷,通過__iter__每次返回壹個獨立的叠代器,就可以保證不同的叠代過程不會互相影響。而生成器表達式之類的結果往往是壹次性的,不可以重復遍歷,所以直接返回壹個Iterator就好。讓Iterator也實現Iterable的兼容就可以很靈活地選擇返回哪壹種。
總結來說Iterator實現的__iter__是為了兼容Iterable的接口,從而讓Iterator成為Iterable的壹種實現。
補充壹下題主對於for的理解基本上是正確的,但仍然有壹點點偏差:for為了兼容性其實有兩種機制,如果對象有__iter__會使用叠代器,但是如果對象沒有__iter__,但是實現了__getitem__,會改用下標叠代的方式。我們可以試壹下:
>>> class NotIterable(object):
... def __init__(self, baselist):
... self._baselist = baselist
... def __getitem__(self, index):
... return self._baselist[index]
...
>>> t = NotIterable([1,2,3])
>>> for i in t:
... print i
...
1
2
3
>>> iter(t)
<iterator object at 0x0345E3D0>
當for發現沒有__iter__但是有__getitem__的時候,會從0開始依次讀取相應的下標,直到發生IndexError為止,這是壹種舊的叠代協議。iter方法也會處理這種情況,在不存在__iter__的時候,返回壹個下標叠代的iterator對象來代替。壹個重要的例子是str,字符串就是沒有__iter__接口的。