有一个使用"标签的记录器"和其他一些虚线命名空间事件来分割事件。我的程序在各个类中实现逻辑,其中大多数都是继承的,但有些是mixins。
如何干净地拥有各种级别的继承,建立最终对象可用的项目列表,包括多继承/ mixins?重载一切并调用子类的东西有点工作(mixins除外),但有点冗长(如果我做了一些疯狂的MRO东西会更加冗长)
class Base(object):
def tags(self):
return ['project-base']
class DoThinger(Base):
def tags(self):
return super(DoThinger, self).tags() + ['thinger']
class SpecialThinger(DoThinger):
def tags(self):
# OK, if verbose
return super(SpecialThinger, self).tags() + ['special-1']
class SprinklesMixin(object):
def tags(self):
return ['sprinkles']
class SprinkleThinger(DoThinger, SprinklesMixin):
def tags(self):
# would need to do some magic MRO stuff
return super(SprinkleThinger, self).tags() + ['specialsprinkles']
print(SpecialThinger().tags()) # -> ['project-base', 'thinger', 'special-1']
print(SprinkleThinger().tags()) # -> ['project-base', 'thinger', 'specialsprinkles']
# (missing 'sprinkles' ^)
理想情况下,我想做类似下面的事情,所以我不会经常重复逻辑,但我不确定...
中的内容。
class Base(object):
_tags = ['project-base']
def tags(self):
... # something...
return []
class DoThinger(Base):
_tags = ['thinger']
class SpecialThinger(DoThinger):
_tags = ['special-1']
class SprinklesMixin(object):
_tags = ['sprinkles']
class SprinkleThinger(DoThinger, SprinklesMixin):
_tags = ['specialsprinkles']
assert set(SpecialThinger().tags()) == {'project-base', 'thinger', 'special-1'}
assert set(SprinkleThinger().tags()) == {'project-base', 'thinger', 'sprinkles', 'specialsprinkles'}
答案 0 :(得分:0)
这是元类的“典型”用例。 Python中的普通类创建过程使用“类型”元类:它负责创建支持多重继承的正确__mro__
属性。通过扩展元类行为,我们可以使用_tags
在类创建时扩展__mro__
属性:
class MetaBase(type):
def __init__(cls, name, bases, dct):
new_tags = set()
for ancestor in cls.__mro__:
new_tags.update(getattr(ancestor, "_tags", set()))
cls.tags = new_tags
class Base(metaclasMetaBase):
_tags = ['project-base']
# In Python 2.x, the class declaration is like:
class Base(object):
__metaclass__ = MetaBase
另一种选择是让元类在类中保存_tags
的描述符,在请求时计算每个类的“tags_”。它应该起作用,但可能会产生严重的副作用。比如,这些类的实例可能不会“看到”该属性 - 只要它是通过类本身的请求:
class MetaBase(type):
@property
def tags(cls):
a = set()
for supercls in cls.__mro__:
a.update(getattr(supercls, "_tags", set()))
return a