2015-09-02 143 views
1

我正在开发一个项目,我想让我的一个类可迭代。据我所知,我可以使用元类来做到这一点。TypeError:'type'对象不可迭代 - 迭代对象实例

首先我想了解元类是如何工作的。因此,我想介绍一下我自己做一个汽车类的练习。所以在这里我想让我的Car类对象可迭代,然后我想在主函数中打印它们的名称。

的代码示例如下:

__author__ = 'mirind4' 

class IterableCar(type): 
    def __iter__(self): 
     return iter(self.__name__) 

class Car(object): 
    __metaclass__ = IterableCar 

    def __init__(self, name): 
     self.name = name 


if __name__=='__main__': 

    car1 = Car('Mercedes') 
    car2 = Car('Toyota') 
    for cars in Car: 
     print (cars.name) 

但不幸的是我得到了一个类型错误:

TypeError: 'type' object is not iterable 

你会这么好心地告诉我哪里做的错误在我的代码?到目前为止,我已经在这个网站和互联网上检查过类似的问题问题,但我不知道问题出在哪里。我正在使用python 3.4。 在此先感谢!

+2

你有'汽车在汽车'。汽车是一个类的定义。你期望做什么?你的意思是把'car1'和'car2'放入一个列表并迭代它?(我发现你的问题的顶部是“让一个类可迭代”的问题,但不清楚你想要什么。'Car'似乎不代表任何类型的集合。) –

+0

@ Two-BitAlchemist - 我认为OP要它产生'C - A - R' ...有趣的概念使一个可迭代的_class _... – mgilson

+0

@mgilson我真的会猜测OP希望它返回到目前为止创建的每个实例,我怀疑是可能的,但我们会看到。 –

回答

4

据我可以告诉,使得类对象可迭代通过使用元类工作得很好:

from __future__ import print_function 

class IterableCar(type): 
    def __iter__(cls): 
     return iter(cls.__name__) 

class Car(object): 
    __metaclass__ = IterableCar 

    def __init__(self, name): 
     self.name = name 


if __name__=='__main__': 

    car1 = Car('Mercedes') 
    car2 = Car('Toyota') 
    for cars in Car: 
     print (cars) 

结果:

mgilson$ python ~/sandbox/test.py 
C 
a 
r 

这里有一个例子,我居然追踪产生的汽车:

from __future__ import print_function 
import weakref 

class IterableCar(type): 

    _cars = weakref.WeakSet() 

    def __iter__(cls): 
     return iter(cls._cars) 

    def add_car(cls, car): 
     cls._cars.add(car) 


class Car(object): 
    __metaclass__ = IterableCar 

    def __init__(self, name): 
     self.__class__.add_car(self) 
     self.name = name 


if __name__=='__main__': 

    car1 = Car('Mercedes') 
    car2 = Car('Toyota') 
    for cars in Car: 
     print (cars.name) 

请注意,如果你使用python3.x,使用你做一个元类:

class Car(metaclass=IterableCar): 
    ... 

不是:

class Car(object): 
    __metaclass__ = IterableCar 

这可能解释了您遇到的问题。

+0

'weakref'模块可以用来修复内存泄漏。 –

+0

@DanD。 - 是的'weakref.WeakSet'可能是最容易使用的对象,可以在这里帮助,但这不在我想这个问题的范围之内......(因为我们甚至不知道OP在尝试着什么做...) – mgilson

+0

@DanD。 - 更新了'WeakSet' – mgilson

2

要跟踪创建的类的实例,我们将首先为每个由元类创建的类添加_cars属性。这将被设置为弱引用,以便类本身不会阻止未使用的实例被垃圾收集。

class IterableCar(type): 
    def __new__(meta, name, bases, attrs): 
     attrs['_cars'] = weaker.WeakSet() 
     return type.__new__(meta, name, bases, attrs) 

要添加实例,我们将覆盖__call__。本质上,这是您在定义类本身时通常放置在__new____init__中的代码的位置。

def __call__(cls, *args, **kwargs): 
     rv = type.__call__(cls, *args, **kwargs) 
     cls._cars.add(rv) 
     return rv 

而且使课堂迭代通过遍历其实例集,

def __iter__(self): 
     return iter(self._cars) 

使用IterableCar会自动跟踪其实例的任何类。

class Car(metaclass=IterableCar): 
    def __init__(self, name): 
     self.name = name 

car1 = Car('Mercedes') 
car2 = Car('Toyota') 
for cars in Car: 
    print(cars.name) 
+0

不错。现在,如果您只是将它设置为WeakSet来修复“内存泄漏”,那么您将全部设置为:-)。 – mgilson

+0

而且,为了完整性,我们还需要添加'__iter__'(它将迭代返回'iter(cls._cars)') – mgilson

+0

两个优点(忽略第一个,忘记第二个)。 – chepner