使用Mixin扩展class属性

时间:2016-11-15 12:39:11

标签: python

我想编写一个可以扩展最终父类属性而不是替换它的Mixin。例如:

class Base(object):
    my_attr = ['foo', 'bar']

class MyMixin(object):
    my_attr = ['baz']

class MyClass(MyMixin, Base):
    pass

print(MyClass.my_attr)
  

['巴兹']

如何将MyMixin写为MyClass.my_attr并将['foo', 'bar', 'baz']作为值?

答案可以是MyClass中的合并,但我想知道是否可以在 MyMixin 中进行合并。与MetaClass或其他东西一样?

3 个答案:

答案 0 :(得分:2)

如果你真的想用mixin在类属性上执行此操作,那么你必须使用自定义元类并将Base之后的mixin放入mro中(这意味着它赢得了#t覆盖基类中的任何内容,只需添加到其中):

class Base(object):
    my_attr = ['foo', 'bar']

class MyMixinBase(type):
    def __init__(cls, name, parents, attribs):
        my_attr = getattr(cls, "my_attr", None)
        if my_attr is None:
            cls.my_attr = ["baz"]
        elif "baz" not in my_attr:
            my_attr.append("baz")


class MyMixin(object):
    __metaclass__ = MyMixinBase

class MyClass(Base, MyMixin):
    pass

print(MyClass.my_attr)

这使得代码非常复杂......此时,仅使用MyMixinBase作为MyClass的元类将产生相同的结果:

class MyOtherClass(Base):
    __metaclass__ = MyMixinBase

print(MyOtherClass.my_attr)

对于这样的用例,类装饰器工作得很好:

def with_baz(cls):
    my_attr = getattr(cls, "my_attr", None)
    if my_attr is None:
        cls.my_attr = ["baz"]
    elif "baz" not in my_attr:
        my_attr.append("baz")
    return cls

@with_baz
class AnotherClass(Base):
    pass

print(AnotherClass.my_attr)

答案 1 :(得分:0)

delete
  

['baz','foo','bar']

您必须手动合并它们。

答案 2 :(得分:0)

您不能这样做,因为您的第二堂课无法访问第一堂课。一种方法是从每个类中获取null my_attr并将它们添加到一起。如果您因任何原因不想这样做,您可以访问所有基地的my_calss并链接它们:

my_attr