我有以下类层次结构:
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__
负责处理子类声明的项目。现在情况可能是祖先链中有多个类(示例中为Foo
和Bar
)并且都需要声明项目。但是,在上面的示例中,Foo
的声明被忽略。
有哪些可能的解决方案,Base.__init__
将所有项目考虑在祖先链中?
(仅假设单继承和Python 2.7)
type
:与this answer类似,我可以使用Bar
声明type
并设置{'items': ['bar'] + Foo.items}
。但是这会使代码高度不可读,而且我也不喜欢对基类的显式引用。使用装饰器:
def extend_items(cls):
cls.items.extend(cls.__bases__[0].items)
return cls
但是,此解决方案将责任转移到子类(开发人员)以及任何祖先声明项目是否未知的事实。当然,每当声明项目时,都可以使用装饰器,但这种感觉就像加倍工作一样,如果装饰器(意外地)被遗漏,它将破坏应用程序。
items
扩展__bases__[0].items
。但是,这还需要额外的工作,即设置__metaclass__
属性,此外如果你需要使用另一个元类,那么它已被阻止。在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
而不是儿童班。