使类可迭代尊重继承

时间:2016-01-16 21:28:17

标签: python inheritance metaclass iterable

使用元类(这里有一些其他答案),简单地使类可迭代很容易。但是,我希望使一个类可迭代,并且还允许一个基于继承"迭代子组#34;。我的一个例子:

class IterPartRegistry(type):
    def __iter__(cls):
        return iter(cls._registry)


class A(object, metaclass=IterPartRegistry):
    _registry = []
    def __init__(self, name):
        self.name = name
        self._registry.append(self)

class B(A):
    pass

class C(A):
    pass


A("A - first")
B("B - first")
B("B - second")
C("C - first")

for t in A:
    print(t.name)

print(" --- ")
for t in B:
    print(t.name)

exit()

第一个循环有效 - 它遍历" A"的所有实例和子节点。但是,第二个循环应该只运行在" A"的特定子组上。 - 那些是孩子的例子" B" (或进一步的孩子)。

(如何)这可以实现最简单?通过这种方式添加更多的子类需要最少量的工作/更改?

2 个答案:

答案 0 :(得分:3)

您可以使用isinstance来确保您只获得类实例

在你的代码中,它改变了一行:

class IterPartRegistry(type):
    def __iter__(cls):
        return (c for c in cls._registry if isinstance(c, cls))

答案 1 :(得分:2)

您可以让每个类通过赋予每个类来维护自己的实例列表 它自己的_registry类属性。然后,而不是检查每个 实例属于特定类,您可以为_registry的每个子类迭代cls中的所有值。要找到这些子类,您可以使用 cls.__subclasses__()方法:

import itertools as IT
class IterPartRegistry(type):
    def __init__(cls, name, bases, attrs):
        super(IterPartRegistry, cls).__init__(name, bases, attrs)
        cls._registry = []
    def __iter__(cls):
        yield from cls._registry
        for subcls in cls.__subclasses__():
            yield from subcls

class A(object, metaclass=IterPartRegistry):
    def __init__(self, name):
        self.name = name
        self._registry.append(self)

class B(A): pass

class C(A): pass

class D(B, C): pass

A("A - first")
B("B - first")
B("B - second")
C("C - first")
D("D - first")

for t in A:
    print(t.name)

print(" --- ")
for t in B:
    print(t.name)

产量

A - first
B - first
B - second
D - first
C - first
D - first
 --- 
B - first
B - second
D - first