[英]super().__init__(...) and default values
Preamble前言
This is a rather basic question, I realize, but I haven't been able to find a sturdy reference for it, which would likely be a mixture of technical details and best practices for well-behaved classes.我意识到这是一个相当基本的问题,但我无法找到可靠的参考资料,这可能是技术细节和表现良好的课程的最佳实践的混合体。
Question问题
When a parent and child class both define the same initialization parameter, but with default values, what's the best way to get sane behavior when the child class is created?当父子 class 都定义相同的初始化参数但使用默认值时,创建子 class 时获得理智行为的最佳方法是什么?
My assumptions are:我的假设是:
__init__
methods may be more sophisticated than just setting self.foo = foo
for their arguments - they may transform it before storing, use it to set other params, etc. and I'd like to be as respectful of that as possible. __init__
方法可能比仅仅为他们的 arguments 设置self.foo = foo
更复杂 - 他们可能会在存储之前对其进行转换,使用它来设置其他参数等,我希望尽可能尊重这一点。__init__
parameters and for attributes.__init__
参数和属性,子类永远不会破坏其父类的接口。 Having a different default value is not considered "breaking". Examples例子
In general, my idea of a "best practice" template for a derived class looks like this:一般来说,我对派生 class 的“最佳实践”模板的想法如下所示:
class Child(Parent):
def __init__(self, arg=1, **kwargs):
self.arg = arg
super().__init__(**kwargs)
That works well in most situations - deal with our stuff, then delegate all the rest to our superclass.这在大多数情况下都很好——处理我们的东西,然后将所有 rest 委托给我们的超类。
However, it doesn't work well if arg
is shared by both Child
and Parent
- neither the caller's argument nor the Child
default are respected:但是,如果
arg
由Child
和Parent
共享,则效果不佳 - 调用者的参数和Child
默认值都不受尊重:
class Parent:
def __init__(self, arg=0):
self.arg = arg
class Child(Parent):
def __init__(self, arg=1, **kwargs):
self.arg = arg
super().__init__(**kwargs)
print(Child(arg=6).arg)
# Prints `0` - bad
A better approach is probably for Child
to acknowledge that the argument is shared:更好的方法可能是让
Child
承认该论点是共享的:
class Parent:
def __init__(self, arg=0):
self.arg = arg
class Child(Parent):
def __init__(self, arg=1, **kwargs):
super().__init__(arg=arg, **kwargs)
print(Child(arg=6).arg)
# Prints `6` - good
print(Child().arg)
# Prints `1` - good
That successfully gets the defaults working according to expectations.这成功地使默认值按预期工作。 What I'm not sure of is whether this plays well with the expectations of
Parent
.我不确定这是否符合
Parent
的期望。 So I think my questions are:所以我认为我的问题是:
Parent.__init__
does some Fancy Stuff with arg
and/or self.arg
, how should Child
be set up to respect that?Parent.__init__
用arg
和/或self.arg
做了一些花哨的东西,那么应该如何设置Child
来尊重它?Parent
and how self.arg
is used?Parent
的内部以及如何使用self.arg
了解太多? Or are there reasonable practices that everyone can follow to draw that part of the interface contract in a clean way?Parent.__init__
only expects that the caller may choose to omit an argument for the arg
parameter. Parent.__init__
只期望调用者可以选择省略arg
参数的参数。 It doesn't matter if any particular caller ( Child.__init__
, in this case) always provides an argument, nor does it matter how the caller produces the value it passes.任何特定的调用者(在这种情况下为
Child.__init__
)总是提供参数并不重要,调用者如何产生它传递的值也无关紧要。
Your third example is what I would write, with the addition that Parent.__init__
itself also uses super().__init__
: it doesn't assume that it's the end of whatever MRO is in force for its self
argument.你的第三个例子就是我要写的,除了
Parent.__init__
本身也使用super().__init__
:它不假设它是任何 MRO 对其self
参数有效的结束。
class Parent:
def __init__(self, arg=0, **kwargs):
super().__init__(**kwargs)
self.arg = arg
class Child(Parent):
def __init__(self, arg=1, **kwargs):
super().__init__(arg=arg, **kwargs)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.