迭代ITERABLE类的实例

时间:2017-08-23 15:18:22

标签: python

我定义了以下类

class Person(object):        
    _counter = 0
    _instances = []

    def __init__(self, nam):
        self.name = nam
        self._instances.append(self)
        self._id = Person._counter + 1
        Person._counter+=1        

    def __repr__(self):
        return f'{self._id} : Person({self.name})'    

    def __iter__(self):
        return self

    def __next__(self):
        pass

    @classmethod
    def iterate(cls):
        return [p for p in Person._instances]

我可以用

迭代这个类的实例
[p for p in Person._instances]

我想了解如何通过调用

来获得相同的结果
[p for p in Person]

我搜索了许多类似的问题,我尝试了几个建议的答案,没有任何运气。我正在使用Python 3.6 Anaconda x64以及我在解释器上测试的所有解决方案我都回来了

  [p for p in Person]
  TypeError: 'type' object is not iterable

你能否详细写下我如何能成功执行这个[p for person in Person]调用以获取与Person.iterate()和Person._instances相同的列表?

2 个答案:

答案 0 :(得分:8)

您可以在元类上定义__iter__以使元类实例(即Person)可迭代:

class metaclass(type):
   def __iter__(cls):
       return iter(getattr(cls, '_instances', []))

class Person(metaclass=metaclass):  
    # __metaclass__ = metaclass Python 2
    ...

答案 1 :(得分:0)

为了清楚起见,我已经包含了解决方案和一些测试数据,因为它已经被" Moses Koledoye" " chepner"还有一个有用的评论。我试图考虑到这一点。

解决方案

class PersonMeta(type):
    _counter = 0     
    _instances = []

    def __iter__(self):
        return iter(getattr(self, '_instances', []))


class Person(metaclass=PersonMeta):

    def __init__(self, nam):
        self.name = nam
        Person._instances.append(self)
        self._id = Person._counter + 1
        Person._counter+=1        

    def __repr__(self):
        return f'{self._id} : Person({self.name})'    

输出

In [70]: [p for p in Person]
Out[70]: 
[1 : Person(James),
 2 : Person(George),
 3 : Person(Jack),
 4 : Person(Mary),
 5 : Person(Sue),
 6 : Person(James),
 7 : Person(George),
 8 : Person(Jack),
 9 : Person(Mary),
 10 : Person(Sue)]

理想情况下,我希望看到Metaclass和Class之间更明确的分离。但我不知道如何将以下语句转移到MetaPerson。这是一个好主意吗 ?你能帮我解决这个问题吗?

Person._instances.append(self)    
Person._counter+=1