【问题标题】:Multiple Mixins and properties多个 Mixin 和属性
【发布时间】:2017-01-21 01:03:17
【问题描述】:

我正在尝试创建一个具有自己属性的 mixin 类,但由于该类没有 init 来初始化属性后面的“隐藏”变量。

class Software:

    __metaclass__ = ABCMeta

    @property
    def volumes(self):
        return self._volumes

    @volumes.setter
    def volumes(self, value):
        pass

class Base(object):

    def __init__(self):
        self._volumes = None

class SoftwareUser(Base, Software):

    def __init__(self):
        super(Base, self).__init__()

所以上面是我想出的最好的解决这个问题的方法,但现实是 _volumes 并不真正属于基础。我可以在 Software 类中添加一个 init,但是 super 调用在两个 mixins 上都不起作用。

第二个是我需要多个 mixin,具体取决于传入的调用,它们总是需要 base,但是 mixins 会发生变化,所以我真的不想要没有为该调用混合的 mixins 中的变量。

有没有一种方法可以让 mixin 将它的变量添加到类中,如果它被混合或者动态调用 mixin 类的 init?。

如有任何问题,请告诉我。

谢谢

【问题讨论】:

  • 我不清楚您所说的 “我可以向 Software 类添加一个 init,但随后 super 调用对两个 mixins 都不起作用”。所有三个类都应该正确实现__init__ 并初始化它们需要的任何属性。
  • 所以我的意思是在上面的示例中添加一个带有 _volumes 变量的 init 到软件类,但是如果我这样做并且它与基类混合在一起,就像它在example(SoftwareUser),则不会调用 Software 类的 init,只会调用 Base init
  • 如果您正确实现它们,则不会,以确保调用 MRO 中的任何其他实现。只有Base不应该调用super,它应该是last继承的类。
  • 但是它们没有在继承链中运行,所以我认为这不起作用,除非我遗漏了什么。我目前正在看这个stackoverflow.com/a/6100595/1638158 也许这有点过头了,如果有办法简化,那么我很开放
  • 您正在将一个类混合到一个继承链中。它需要通过在 MRO 中调用其任何方法的下一个实现来正确处理该问题,无论它混入什么类。混合类应该出现在使用它们的子类的定义中基类之前。

标签: python mixins


【解决方案1】:

是的,这太复杂了。一个类(包括 mixins)应该只负责调用 MRO 中的 next 实现,而不是编组所有这些实现。试试:

class Software:

    @property
    def volumes(self):
       return self._volumes

    @volumes.setter
    def volumes(self, value):
       pass

    def __init__(self):
        self._volumes = None
        super().__init__()  # mixin calls super too


class Base(object):

    def __init__(self):
        other_vars = None


class SoftwareUser(Software, Base):  # note order

    def __init__(self):
        super().__init__()  # all you need here

【讨论】:

  • 啊,谢谢,这是缺少的部分,我明白了。 super 将遵循 MRO 并不是那么直观,我期望必须从“软件”类继承 base 才能使用 super 调用
  • 注意:super().method()只适用于Python 3。在2中,你需要做super(ThisClass, self).method()
  • 我认为Software.__init__ 应该有签名(self, *args),并且应该将*args 传递给它的super().__init__ 是否正确?否则,如果 Base.__init__ 被修改为接受参数,SoftwareUser.__init__ 就不可能传递它们?
  • @Cai 是的,通常在实现(尤其是多重)继承时,您应该处理 *args**kwargs
【解决方案2】:

好的,这就是我想出的,如果我让这种方式变得过于复杂,我愿意接受其他答案。

class Software:

    @property
    def volumes(self):
       return self._volumes

    @volumes.setter
    def volumes(self, value):
       pass

    def __init__(self):
        self._volumes = None


class Base(object):

    def __init__(self):
        other_vars = None


class SoftwareUser(Base, Software):

    def _bases_init(self, *args, **kwargs):
        for base in type(self).__bases__:
            base.__init__(self, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        self._bases_init(*args, **kwargs)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多