简体   繁体   English

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

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

I want to use Mixins more in python and like the pattern of:我想在 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!"

But I have yet to crack the problem of having parameterized mixins.但是我还没有解决参数化mixin的问题。 In my job I see a lot of explicit __init__ calls to super classes alá在我的工作中,我看到很多对超类的显式__init__调用 alá

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

I see the use in breaking up the parameters and distributing them explicitely, but I would like to keep the "passthrough" property the __init__ of the above Mixin example has.我看到了分解参数并显式分配它们的用途,但我想保留上述 Mixin 示例的__init__具有的“passthrough”属性。

I could only think of having all arguments to the Mixin as specific keyword arguments, which get pop 'ed out of the **kwargs parameter or only relying on fields being present in the mixin and having to set them before, which would turn the last example into:我只能想到将 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)

The key to using super properly is that every class involved in the hierarchy should assume that everyone else will also call super .正确使用super的关键是层次结构中涉及的每个类都应该假设其他人也会调用super That's true for every class except object , which is always the root class in any inheritance hierarchy.对于除object之外的每个类都是如此,它始终是任何继承层次结构中的根类。

For your example对于你的例子

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

that means that A , B , and FloorMixin should all calling super().__init__ , and you should use keyword arguments when instantiating A so that there are no ordering-based conflicts.这意味着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="...")

The method resolution order for A is [A, B, FloorMixin, object] , so each call to super().__init__ calls __init__ from the next class in line. A的方法解析顺序是[A, B, FloorMixin, object] ,因此每次调用super().__init__ __init__从行中的下一个类调用__init__ A.__init__ calls B.__init__ , which calls FloorMixin.__init__ , which calls object.__init__ . A.__init__调用B.__init__ ,后者调用FloorMixin.__init__ ,后者调用object.__init__ Importantly, note that this means that at runtime , B.__init__ calls __init__ of a class that the author of B may not even have known about.重要的是,请注意,这意味着在运行时B.__init__调用B的作者甚至可能不知道的类的__init__ That's why it's important to accept unexpected keyword arguments and to pass them on.这就是为什么接受意外的关键字参数并传递它们很重要的原因。

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

相关问题 如何在 Python 中显式释放内存? - How can I explicitly free memory in Python? 如何在没有显式扩展名的情况下使用MATLAB或python区分.gif和.jpg文件? - How can I tell the difference between a .gif and a .jpg file using MATLAB or python without having the extension explicitly? 数据驱动 - 如何在 Python 中使用选择性 args/params 作为参数化的一部分? - Data Driven - How can I use selective args/params as part of parameterize in Python? 如何为 Python 变量显式指定 class 类型? - How can I explicitly specify a class type for a Python variable? 如何在python中显式设置终端大小? - How can I explicitly set the terminal size in python? 我如何才能明确地看到“自我”在 python 中的作用? - How can I explicitly see what 'self' does in python? 有没有办法在python中执行文件中的所有函数而不显式调用它们? - Is there a way in python to execute all functions in a file without explicitly calling them? 使用类而不在python中调用构造函数 - Using a class without calling the constructor in python 在python中构造一个class而不直接调用构造函数 - Constructing a class in python without directly calling the constructor 如何安全地参数化动态python mysql查询? - How do I securely parameterize a dynamic python mysql query?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM