如何在Python中改进mixin结构?

时间:2016-09-28 13:35:29

标签: python mixins

我在Python中有一个简单的mixin结构。代码应该是非常自我解释的:

class Base:
    def __init__(self):
        pass

class MixinA:
    def __init__(self):
        self.x = 0
        self.y = 1
    def a(self):
        print('A: x = ' + str(self.x) + ', y = ' + str(self.y))

class MixinB:
    def __init__(self):
        self.x = 2
        self.z = 3
    def b(self):
        print('B: x = ' + str(self.x) + ', z = ' + str(self.z))

class MyFirstMix(MixinA, MixinB, Base):
    def __init__(self):
        Base.__init__(self)
        MixinB.__init__(self)
        MixinA.__init__(self)

class MySecondMix(MixinA, Base):
    def __init__(self):
        Base.__init__(self)
        MixinA.__init__(self)

我想稍微提高一点,所以这会导致3个问题:

  1. MixinAMixinB都有成员x。有没有办法确保,每个班级只看到自己的x ?据我所知:不,没有。
  2. 为混合类中的每个mixin调用构造函数稍微麻烦一些。有没有办法自动调用所有构造函数或执行具有相同效果的操作?
  3. 有没有一种方法可以在线显示动态混合,而无需显式创建类?我正在寻找类似的语法:mix = Base() with MixinA
  4. 如果我提出的结构完全错误,我也会就如何处理mixin提出其他建议。

2 个答案:

答案 0 :(得分:0)

当您的继承方案开始遭受这些问题时,现在应该考虑使用一种名为 composition 的技术。对主题here的可读性很好的介绍。 Wikipedia example稍微不易访问,但如果您可以处理其他编程语言也很有用。 This StackExchange question也提供了有用的讨论。

最简单的,而不是继承自SomeParent并在Mixin类中混合的类,而是让SomeParent个实例分别创建Mixin的实例,用它来访问mixin类的功能。

答案 1 :(得分:0)

对于固有的python类,我相信你需要知道一些技巧:

  1. python2和python3中的类是完全不同的。 Python2支持旧式类,但python3仅支持新式类。简单来说:在python3中,类总是来自基类object,即使你没有明确地使用它。查看Difference-between-Old-New-Class

  2. 方法解析订单(MRO)。这决定了派生类如何搜索固有成员和函数。请参阅MRO

  3. super功能。结合MRO,您可以轻松调用父成员或函数,而无需明确知道父类的名称。请参阅Super

  4. 现在提出问题:

    1. MixinA和MixinB都有一个成员x。有没有办法确保,每个班级只看到自己的x?
    2. 我不会理解你的意思。引用类成员时,必须通过其实例或类引用它。因此instance_of_MixinA.xinstance_of_MixinB.x是分开的。如果您正在讨论类MyFirstMix(MixinA, MixinB, Base),那么它取决于如何调用__init__函数。在您的代码中,首先按x填充MixinB,然后按MixinA重置其值。

      1. 为混合类中的每个mixin调用构造函数稍微麻烦一些。有没有办法自动调用所有构造函数或执行具有相同效果的操作。
      2. 你的名字让它变得不可能。你必须调用所有构造函数。

        1. 有没有一种方法可以在线显示动态混合,而无需显式创建类?
        2. 我不确定。但是我可以给你一些建议:在def class(python3,如果你使用python2处理__init__)时尝试在super成员之外:

          class Base:
              def __init__(self):
                  pass
          
          
          class MixinA:
              x = 0
              y = 1
          
          
          class MixinB:
              x = 2
              z = 3
          
              def b(self):
                  print('B: x = ' + str(self.x) + ', z = ' + str(self.z))
          
          
          class MyFirstMix(MixinA, MixinB, Base):
              def __init__(self):
                  super().__init__()
          
          
          class MySecondMix(MixinA, Base):
              def __init__(self):
                  super().__init__()
          

          __init__之外的变量与内部变量的行为不同:外部变量属于类,将为此类的所有实例填充,而内部变量仅属于实例(由self引用时你定义了类),只有在调用__init__时才会填充。这就是为什么你不能使用super来调用所有构造函数--- super只调用优先级父__init__的原因。见variables-outsite-inside-init

          这是Mixin类的一个很好的解决方案。在上面的代码中,MyFirstMix同时包含MixinAMixinB,其成员都是类成员(__init__之外)。因此MyFirstMix的实例将固有MixinAMixinB的所有班级成员,而不会调用__init__。此处MixinAMixinB拥有相同的班级成员x,但MRO确定MyFirstMix的实例引用x,{{1}应该返回x

          希望这会有所帮助。谢谢!