Полный, правильный и правильный ответ.
for
, как для циклов, так и для списков, вызывает iter()
на X
.iter()
возвратит итерацию, если X
имеет либо метод __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]
Использование:
>>> 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)
Использование:
>>> 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
Использование:
>>> 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
Это последний способ, который я бы порекомендовал.Легко и эффективно.