【问题标题】:Make class iterable respecting inheritance使类可迭代尊重继承
【发布时间】:2016-04-22 07:15:11
【问题描述】:

使用元类很容易让一个类可迭代(这里有一些其他答案)。但是,我希望使一个类可迭代,并且还使一个类能够“基于继承迭代一个子组”。我的使用示例:

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”(或下一行的子)的实例。

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

【问题讨论】:

    标签: python inheritance metaclass iterable


    【解决方案1】:

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

    在您的代码中,仅更改一行:

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

    【讨论】:

    • 这看起来很不错。只是想知道 - 迭代时不会在每次我转到下一个元素时迭代 _registry。 (换句话说,现在迭代 n 个元素需要 O(n^2) 而不是 O(n) 时间?
    • 既然生成器返回的迭代器就是生成器本身,那可能就是return (c for c in cls._registry if isinstance(c, cls))
    • @paul23,不,它只会迭代一次,O(n)
    【解决方案2】:

    你可以让每个类维护自己的实例列表,方法是给每个类 它自己的_registry 类属性。然后,而不是检查每个 instance 属于特定类,您可以改为迭代 _registrys 中每个 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
    

    【讨论】:

    • 糟糕,我的错误。这可以通过递归迭代子类来解决。我已经编辑了帖子以说明我的意思。
    猜你喜欢
    • 2014-07-18
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    相关资源
    最近更新 更多