在Python中迭代给定类的对象实例

20

给定一个保留其对象注册表的类:

class Person(object):
   __registry = []

   def __init__(self, name):
       self.__registry.append(self)
       self.name = name
我该如何使以下的代码工作(不使用 Person.__registry):
for personobject in Person:
    print personobject

在研究过程中,我发现可以使用具有__getitem__方法的__metaclass__。你有什么想法吗?这会是什么样子?


嗯,不要把一个丑陋的Hack变得好看。 - Iraimbilanja
3个回答

33
您可以使用一个简单的元类使您的类对象可迭代。
class IterRegistry(type):
    def __iter__(cls):
        return iter(cls._registry)

class Person(object):
    __metaclass__ = IterRegistry
    _registry = []

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

我还将__registry更改为_registry,以便从元类更容易地访问。

>>> p = Person('John')
>>> p2 = Person('Mary')
>>> for personobject in Person:
...     print personobject
...
<person.Person object at 0x70410>
<person.Person object at 0x70250>

非常好的提示:我不知道这个 :) - jkp
为什么把def __iter__放在Person类里面就不能工作呢?只是好奇。 - Paolo Bergantino
2
@Paolo 在 Person 类中添加 iter 方法可以使 Person 实例可迭代,而在元类中添加它可以使 Person 类本身可迭代,这正是我们需要的。 - dF.
3
你好,我已经在Python 3.6.0 Anaconda 64位版本中测试了这段代码,但它无法正常工作。我已经修复了print语句,但是会出现TypeError: 'type' object is not iterable错误。我是Python的新手,但我猜测这可能是因为在Python 3.6中可迭代对象的规范已经改变了。 - Athanassios
1
当你删除类的实例时,注册表不会得到更新。 - vrleboss
@Athanassios,有关Python 3,请参见遍历对象实例使类可迭代 - Hans Ginzel

16

首先,不要使用双下划线__的命名方式。它们被Python保留使用。如果你想使用“私有”的命名方式,请使用单下划线_

其次,将这种类型的问题尽可能简单化。不要在一个复杂的问题上浪费太多时间和精力。这是一个简单的问题,保持代码尽可能简单以完成任务。

class Person(object):
    _registry = []

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

for p in Person._registry:
    print p

2
重点是_registry解决方案可能完成此操作的最简单方式。其他任何方式都只是在“给猪涂口红”。 - S.Lott

4

您可以使用以下方法完成:

for item in Person.__registry:
    print(item)

那很明显...但我想让它像这样工作:对于Classname中的项目...(只是为了美观...) - Titusz
你需要让你的类可迭代,我猜。 - SilentGhost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接