动态地将类变量添加到继承mixin类

时间:2016-10-05 15:59:35

标签: python python-3.x

我有一个mixin类,它为继承类添加了一些功能,但是mixin需要一些类属性才能出现,为简单起见,我们只说一个属性handlers。所以这就是mixin的用法:

class Mixin:
    pass

class Something(Mixin):
    handlers = {}

如果没有定义,mixin就无法运行,但我真的不想在我想要使用mixin的每个类中指定handlers。所以我通过编写元类来解决这个问题:

class MixinMeta:
    def __new__(mcs, *args, **kwargs):
        cls = super().__new__(mcs, *args, **kwargs)
        cls.handlers = {}
        return cls

class Mixin(metaclass=MixinMeta):
    pass

这正是我想要的方式。但我认为这可能会成为一个巨大的问题,因为元类不能很好地协同工作(我读过各种元类冲突只能通过创建一个解决这些冲突的新元类来解决)。

另外,我不想让handlers属性成为Mixin类本身的属性,因为这意味着必须按照Mixin中的类名存储处理程序类,使代码复杂化。我喜欢让每个班级在他们自己的班级上有他们的处理程序 - 这使他们更简单,但显然这有缺点。

我的问题是,实施此更好的方法是什么?我对metaclasses很新,但他们似乎很好地解决了这个问题。但是,在处理复杂的层次结构时,元类冲突显然是一个巨大的问题,而不必为了解决这些冲突而定义各种元类。

1 个答案:

答案 0 :(得分:5)

你的问题非常真实,Python人们已经想到了Python 3.6(仍未实现)。就目前而言(直到Python 3.5),如果你的属性可以等到第一次实例化你的类,你可以放置cod来在你的mixin类本身的__new__方法上创建一个(类)属性 - 从而避免(额外)元类:

class Mixin:
    def __new__(cls):
         if not hasattr(cls, handlers):
              cls.handlers = {}
         return super().__new__(cls)

对于Python 3.6,PEP 487定义了一个__init_subclass__特殊方法来继续使用mixin类主体。这个特殊方法不是为mixin类本身调用的,而是在type.__new__方法的末尾(" root"元类)为从mixin继承的每个类调用。

class Mixin:
    def __init_subclass__(cls, **kwargs):
         cls.handlers = {}
         return super().__init_subclass__(**kwargs) 

根据PEP的背景文本,其主要动机正是导致您提出问题的原因:当需要简单的类创建自定义时,避免需要元类,以减少在项目中需要不同元类的机会,从而引发元类冲突的情况。