class with __iter__ assigned in constructor not recognized as iterator

匿名 (未验证) 提交于 2019-12-03 09:06:55

问题:

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)) 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!