繁体   English   中英

如何在 python 中参数化 Mixins,而不显式调用它们的构造函数?

[英]How can I parameterize Mixins in python, without calling their constructor explicitly?

我想在 python 中更多地使用 Mixins 并且喜欢以下模式:

class Person:
  [...]

class Greetable:
  greeting: str

  def __init__(*args, **kwargs):
    super().__init(*args, **kwargs)
    ... greeting related setup

  def greet(self):
    print(f"{self.greeting} sir or madam!")

class Sailor(Greetable, Person):
  def __init__(self):
    super().__init__()

    self.greeting = "Ahoy"

>>> Sailor().greet()
"Ahoy sir or madam!"

但是我还没有解决参数化mixin的问题。 在我的工作中,我看到很多对超类的显式__init__调用 alá

class A(B, FloorMixin):
  def __init__(desk, chair, floor):
    B.__init__(self, desk, chair)
    FloorMixin.__init__(floor)

我看到了分解参数并显式分配它们的用途,但我想保留上述 Mixin 示例的__init__具有的“passthrough”属性。

我只能想到将 Mixin 的所有参数作为特定的关键字参数,这些参数会从**kwargs参数中pop ,或者只依赖于 mixin 中存在的字段并且必须在之前设置它们,这将变成最后一个例如到:

class A(FloorMixin, B):
  def __init__(desk, chair, floor):
    self._floor = floor  # FloorMixin expects a _floor attribute

    super().__init__(desk, chair)

正确使用super的关键是层次结构中涉及的每个类都应该假设其他人也会调用super 对于除object之外的每个类都是如此,它始终是任何继承层次结构中的根类。

对于你的例子

class A(B, FloorMixin):
  def __init__(self, desk, chair, floor):
    B.__init__(self, desk, chair)
    FloorMixin.__init__(floor)

这意味着ABFloorMixin都应该调用super().__init__ ,并且在实例化A时应该使用关键字参数,以便没有基于排序的冲突。

class B:
    def __init__(self, desk, chair, **kwargs):
        super().__init__(**kwargs)
        # Do stuff with desk and chair

class FloorMixin:
    def __init__(self, floor, **kwargs):
        super().__init__(**kwargs)
        # Do stuff with floor

class A(B, FloorMixin):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # If there's nothing else to do, you don't
        # even need to define A.__init__

# With keyword arguments, order doesn't matter
# Each __init__ will find the arguments it needs
# and pass on the rest
a = A(floor="...", chair="...", desk="...")

A的方法解析顺序是[A, B, FloorMixin, object] ,因此每次调用super().__init__ __init__从行中的下一个类调用__init__ A.__init__调用B.__init__ ,后者调用FloorMixin.__init__ ,后者调用object.__init__ 重要的是,请注意,这意味着在运行时B.__init__调用B的作者甚至可能不知道的类的__init__ 这就是为什么接受意外的关键字参数并传递它们很重要的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM