问题
Kind of a weird question about iterators. While investigating a different question, I found the following. Here is an iterable that works:
class CacheGen(object):
def __init__(self, iterable):
if isinstance(iterable, (list, tuple, dict)):
self._myiter = iterable
else:
self._myiter = list(iterable)
def __iter__(self):
return self._myiter.__iter__()
def __contains__(self, key):
return self._myiter.__contains__(key)
def __getitem__(self, key):
return self._myiter.__getitem__(key)
Here is a similar iterable that doesn't:
class CacheGen2(object):
def __init__(self, iterable):
if isinstance(iterable, (list, tuple, dict)):
self._myiter = iterable
else:
self._myiter = list(iterable)
self.__iter__ = self._myiter.__iter__
self.__contains__ = self._myiter.__contains__
self.__getitem__ = self._myiter.__getitem__
Note that they are really doing about the same thing, but one delegates, and the other just assigns my class constructor to the list's. Any ideas why? Note that it has an iter function in the class, I can call it directly and get a valid iterator, but the 'normal' functions don't work.
xr = xrange(100)
cg = CacheGen(xr)
list(cg)
[0,1,2,3...
cg2 = CacheGen2(xr)
list(cg2)
TypeError Traceback (most recent call last)
<ipython-input-83-1f4da2c55acb> in <module>()
----> 1 list(cg2)
TypeError: 'CacheGen2' object is not iterable
cg2.__iter__
<method-wrapper '__iter__' of list object at 0x0000000006695C08>
cg2.__iter__()
<listiterator at 0x669c438>
iter(cg2)
TypeError Traceback (most recent call last)
<ipython-input-86-b62853ce1dab> in <module>()
----> 1 iter(cg2)
TypeError: 'CacheGen2' object is not iterable
回答1:
Magic methods like __iter__
are looked up on the class, not the instance, so it doesn't work to assign them on self
. They have to actually exist on the class.
回答2:
The correct way of doing what you want is:
class CacheGen(object):
def __init__(self, iterable):
if isinstance(iterable, (list, tuple, dict)):
self._myiter = iterable
else:
self._myiter = list(iterable)
def __iter__(self):
for value in self._myiter:
yield value
...
回答3:
If you would like to create your own Iterator class,
your class must override the following methods
def __iter__(self)
and
def next(self)
then only your class will be considered as an iterator
the simple example of iterator is,
class MyIter(object):
def __init__(self, val):
self.val = val
def __iter__(self):
return self
def next(self):
if self.val >= 5:
raise StopIteration
self.val += 1
return self.val
print list(MyIter(0))
来源:https://stackoverflow.com/questions/19508548/class-with-iter-assigned-in-constructor-not-recognized-as-iterator