[英]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.这意味着A
、 B
和FloorMixin
都应该调用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.