据我所知,完整且正确的答案。
for
,在 for 循环和列表推导式中,都调用iter()
on X
. iter()
将返回一个可迭代的 ifX
要么有一个__iter__
方法或__getitem__
方法。如果两者都实现的话,__iter__
用来。如果两者都没有,你就会得到TypeError: 'Nothing' object is not iterable
.
这实现了一个__getitem__
:
class GetItem(object):
def __init__(self, data):
self.data = data
def __getitem__(self, x):
return self.data[x]
Usage:
>>> data = range(10)
>>> print [x*x for x in GetItem(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
这是一个实施的例子__iter__
:
class TheIterator(object):
def __init__(self, data):
self.data = data
self.index = -1
# Note: In Python 3 this is called __next__
def next(self):
self.index += 1
try:
return self.data[self.index]
except IndexError:
raise StopIteration
def __iter__(self):
return self
class Iter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
return TheIterator(data)
Usage:
>>> data = range(10)
>>> print [x*x for x in Iter(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如您所见,您需要实现迭代器,并且__iter__
返回迭代器。
您可以将它们组合起来:
class CombinedIter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
self.index = -1
return self
def next(self):
self.index += 1
try:
return self.data[self.index]
except IndexError:
raise StopIteration
Usage:
>>> well, you get it, it's all the same...
但是这样你一次只能有一个迭代器运行。
好的,在这种情况下你可以这样做:
class CheatIter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
return iter(self.data)
但这是作弊,因为你只是重复使用__iter__
的方法list
。
一个更简单的方法是使用yield,然后使__iter__
进入发电机:
class Generator(object):
def __init__(self, data):
self.data = data
def __iter__(self):
for x in self.data:
yield x
最后是我推荐的方式。简单高效。