當解釋器想要迭代訪問一個對象的時候丁侄,會調(diào)用iter(x)
惹苗。
-
iter
方法會檢查對象是否實現(xiàn)了__iter__
方法失尖,如果實現(xiàn)了善榛,就調(diào)用它返回一個迭代器戴而。 - 如果沒有實現(xiàn)
__iter__
砾肺,則去嘗試調(diào)用__getitem__
方法挽霉,解釋器創(chuàng)建一個迭代器,按下表從0開始依次獲取元素变汪。 - 如果上面兩個方法都沒有實現(xiàn)侠坎,則拋出
TypeError
。錯誤信息為:"XXX object is not iterable"裙盾。
需要說明的一點是实胸,在Python 2.X的環(huán)境下,常常有range()
和xrange()
兩種方式來創(chuàng)建一個可迭代對象(在Python 3.X中統(tǒng)一使用range()
闷煤,效果和Python 2.X中的xrange()
一致)童芹。兩者的區(qū)別在于前者返回的是一個計算好的列表,而后者返回的是一個惰性可迭代對象鲤拿。列表并不是迭代器假褪。
>>> a = range(7)
>>> b = xrange(7)
>>> c = (x for x in range(7))
>>> next(a)
TypeError: list object is not an iterator.
>>> next(b)
TypeError: xrange object is not an iterator.
>>> next(c)
0
那么,迭代器和可迭代對象又有什么區(qū)別呢近顷?range
和xrange
對象都可以供多次迭代訪問生音,而迭代器(上文中的c對象)僅可供一次迭代訪問:從下表0開始到StopIteration
。
使用 iter 內(nèi)置函數(shù)可以從可迭代對象獲取迭代器的對象窒升。如果對象實現(xiàn)了能返回迭代器的 __iter__
方法缀遍,那么對象就是可迭代的。序列都可以迭代饱须;實現(xiàn)了 __getitem__
方法域醇,而且其參數(shù)是從零開始的索引,這種對象也可以迭代。
最后用一個自定義的等差數(shù)列來說明可迭代對象的實現(xiàn):
class ArithmeticProgression:
def __init__(self, begin, step, end=None):
self.begin = begin
self.step = step
self.end = end # None -> 無窮數(shù)列
def __iter__(self):
result = type(self.begin + self.step)(self.begin)
forever = self.end is None
index = 0
while forever or result < self.end:
yield result
index += 1
result = self.begin + self.step * index
# 也可以用下面方法來實現(xiàn)
def aritprog_gen(begin, step, end=None):
result = type(begin + step)(begin)
forever = end is None
index = 0
while forever or result < end:
yield result
index += 1
result = begin + step * index
# 或者借助itertools來實現(xiàn)
def aritprog_gen(begin, step, end=None):
import itertools
first = type(begin + step)(begin)
ap_gen = itertools.count(first, step)
if end is not None:
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
return ap_gen