對Python初學者來說,要搞清楚其中的iterable、iterator和generator的分別可不容易。看表面意思,iterable應該是一種可以迭代的東西,iterator是一個用來迭代的東西,generator是一個能產生東西的東西。可是,iterable不是iterator,但卻可以從它身上得到iterator,而iterator也是iterable的,可以從身上得到自己這個iterator,最後generator是個iterator,所以也是iterable的...在說甚麼呢?不急,我們一步步分析。
首先,iterable顯然是一種可以迭代的東西,既然如此,那麼str、list、tuple、set、dict等預設的Python objects都是iterable,都可以將它們用for
語句做迭代,例如:
>>> names = ['Mary', 'Jack', 'Emily', 'Lauren', 'Olivia']
>>> for name in names:
... print(name)
...
Mary
Jack
Emily
Lauren
Olivia
那iterable可以產生iterator又是甚麼意思呢?用dir
函數看看list這個iterable有甚麼方法可以調用:
>>> dir(names)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__',
'__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
返回的結果很長,但我們要注意,names
這個list中有一個叫__iter__
的方法,就是iterable中的這個方法可以產生一個iterator。Python已內建了iter
函數讓我們調用object中的__iter__
方法,不用寫為names.__iter__()
的樣子:
>>> iter(names)
<list_iterator object at 0x03085190>
產生這個iterator用來幹嘛呢?再用dir
函數看看它有甚麼方法可調用:
>>> names_iter = iter(names)
>>> dir(names_iter)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__',
'__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
注意了,iterator和iterable最大的分別是iterator有一個叫__next__
的方法,這個方法可以返回序列中的下一個內容。由於Python也內建了next
函數調用object中的__next__
方法,所以不用寫為names_iter.__next__()
:
>>> next(names_iter)
'Mary'
>>> next(names_iter)
'Jack'
>>> next(names_iter)
'Emily'
可見,每調用一次__next__
方法,序列中的內容就會被讀出一個,直到讀完所有內容,就會引發StopIteration
異常:
>>> next(names_iter)
'Lauren'
>>> next(names_iter)
'Olivia'
>>> next(names_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
另一方面,iterable是沒有__next__
方法的,你不能用next
來從iterable中將序列內容讀出:
>>> next(names)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
不過,iterator中卻有__iter__
方法,這不是iterable中用於產生iterator的方法嗎?究竟是怎麼一回事呢?用names_iter
中的__iter__
方法嘗試產生另一個iterator,但會發現這個iterator就是自己本身:
>>> names_iter2 = iter(names_iter)
>>> names_iter
<list_iterator object at 0x03085280>
>>> names_iter2
<list_iterator object at 0x03085280>
>>> names_iter is names_iter2
True
可見names_iter
和names_iter2
是相同的object,既然它們相同,那麼對names_iter2
使用next
函數,也一樣沒有內容可以讀出了,也會出現StopIteration
異常:
>>> next(names_iter2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
小結一下:
- iterable中有
__iter__
方法,調用它會產生一個對應的iterator。 - iterator中有
__next__
方法,調用它會返回對應iterable序列中的內容。 - iterator中也有
__iter__
方法,調用它會返回自己,由於iterator有iterable中的__iter__
方法,所以說iterator也是iterable的。
我們在下一次再介紹為何要有iterable和iterator,為何不二合為一。