在类定义中扩展基类属性

时间:2016-11-28 14:20:56

标签: python inheritance class-attributes method-resolution-order

我有以下类层次结构:

class Base(object):
    items = []

    def __init__(self):
        # Use items for initialization.
        for item in self.items:
            print item


class Foo(Base):
    # Works, because Base.items is empty.
    items = ['foo']

    def __init__(self):
        super(Foo, self).__init__()


class Bar(Foo):
    # This overrides Foo.items while it should be extended.
    items = ['bar']

    def __init__(self):
        super(Bar, self).__init__()

Base.__init__负责处理子类声明的项目。现在情况可能是祖先链中有多个类(示例中为FooBar)并且都需要声明项目。但是,在上面的示例中,Foo的声明被忽略。

问题

有哪些可能的解决方案,Base.__init__将所有项目考虑在祖先链中? (仅假设单继承和Python 2.7)

  1. 使用type:与this answer类似,我可以使用Bar声明type并设置{'items': ['bar'] + Foo.items}。但是这会使代码高度不可读,而且我也不喜欢对基类的显式引用。
  2. 使用装饰器:

    def extend_items(cls):
        cls.items.extend(cls.__bases__[0].items)
        return cls
    

    但是,此解决方案将责任转移到子类(开发人员)以及任何祖先声明项目是否未知的事实。当然,每当声明项目时,都可以使用装饰器,但这种感觉就像加倍工作一样,如果装饰器(意外地)被遗漏,它将破坏应用程序。

  3. 使用元类:元类可以提供与decorater相同的功能,即通过items扩展__bases__[0].items。但是,这还需要额外的工作,即设置__metaclass__属性,此外如果你需要使用另一个元类,那么它已被阻止。
  4. self.__class__.__mro__中使用Base.__init__

    def __init__(self):
        items = []
        for cls in self.__class__.__mro__:
            try:
                items.extend(cls.items)
            except AttributeError:
                pass
        # Continue using `items`.
    

    这感觉就像最干净的解决方案,因为它不需要在任何子类中进行额外的工作,只需使用items = [...]插入声明即可。将所有项目考虑在内的责任留给Base而不是儿童班。

0 个答案:

没有答案