我想将一个类的所有实例存储在一个列表中,并希望迭代它。
我尝试了以下两种方法:
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
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
。
有人可以解释一下(详细)为什么第二种方法不起作用以及为什么需要使用元类来使另一个类可迭代?
答案 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__()
方法。)