使用__iter__迭代类实例

时间:2015-02-23 14:48:39

标签: python

我想将一个类的所有实例存储在一个列表中,并希望迭代它。

我尝试了以下两种方法:

1使用MetaClasses

class ClassIter(type):
    def __iter__(cls):
        return iter(cls._ClassRegistry)
    def __len__(cls):
        return len(cls._ClassRegistry)         

class MyClass(object):
    __metaclass__ = ClassIter
    _ClassRegistry = []
    def __init__(self,objname):
        self._ClassRegistry.append(self)
        self.name = objname

for x in ["first", "second", "third"]:
    MyClass(x)

for y in MyClass:
    print y.name

2:在Class本身中使用 iter

class MyClass1(object):
    _ClassRegistry = []
    def __init__(self,objname):
        self._ClassRegistry.append(self)
        self.name = objname
    def __iter__(self):
        return iter(self._ClassRegistry)

for x in ["first", "second", "third"]:
    MyClass1(x)

for y in MyClass1:
    print y.name

在这两种解决方案中,前一种方法完美地运行,而后一种解决方案给出了错误TypeError: 'type' object is not iterable

有人可以解释一下(详细)为什么第二种方法不起作用以及为什么需要使用元类来使另一个类可迭代?

2 个答案:

答案 0 :(得分:3)

__iter__等特殊方法不会直接在对象上查找,只能在对象的类型上查找。 Python调用type(object).__iter__(object),而不是object.__iter__(),有效地绕过了正常的对象优先再查找类型(因此从实例到类,从类到元类)。

这样做可以使类型的散列成为可能;如果hash(object)使用了直接在对象上找到的__hash__方法,则永远无法为实例定义带有__hash__方法的自定义类。

元类是类的类型;就像类是实例的类型一样,iter(class)会直接查找type(class).__iter__()而不是class.__iter__

如果 以这种方式工作,则永远无法为您的类实例定义__iter__方法,因为class.__iter__将是一种方法并且要求绑定实例,而如果你在类上迭代则没有这样的实例。

请参阅Python数据模型文档的Special method lookup section

  

对于自定义类,只有在对象类型上定义的特殊方法的隐式调用才能保证正常工作,而不是在对象的实例字典中。

答案 1 :(得分:0)

特殊方法名称总是这样调用:

iter(foo) <--> type(foo).__iter__(foo)

您的第一个解决方案与此调用兼容(type(MyClass)是元类)。你的第二个不是(type(MyClass1) is type,它没有__iter__()方法。)