使用 super() 进行直接多重继承时保持可读性
Maintaining readability when using super() for direct multiple inheritance
对于最基本的多重继承的情况:
class A:
def __init__(self, a):
self.a = a
class B:
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
我不明白为什么要使用 super()
。我想你可以用 kwargs 来实现它,但这肯定不如上面的方法可读。我还没有找到任何支持这种方法的堆栈溢出答案,但对于这种情况,它肯定是最令人满意的吗?
有很多关于这个主题的问题被标记为重复,但对于这个确切的案例没有令人满意的答案。 addresses multiple inheritance and the use of super()
for a diamond inheritance. In this case there is no diamond inheritance and neither parent class have any knowledge of each other, so they shouldn't need to call super()
like 建议。
This answer deals with the use of super
in this scenario but without passing arguments to __init__
like is done here, and this answer 处理传递参数,但又是钻石继承。
class A(object):
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
self.a = kwargs['a']
class B(object):
def __init__(self, *args, **kwargs):
super(B, self).__init__()
self.b = kwargs['b']
class C(A, B):
def __init__(self, *args, **kwargs):
super(C, self).__init__(*args, **kwargs)
z = C(a=1,b=2)
z.b
2
此处使用 super
的一种正确方法是
class A:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
self.a = a
class B:
def __init__(self, b, **kwargs):
super().__init__(**kwargs)
self.b = b
class C1(A, B):
pass
class C2(A, B):
def __init__(self, a, b, **kwargs):
super().__init__(a=a, b=b, **kwargs)
c1 = C1(a="foo", b="bar")
c2 = C2(a="foo", b="bar")
C
的方法解析顺序是 [C, A, B, object]
。每次调用 super()
时,它 returns 是 MRO 中 next class 的代理,基于调用 super()
的位置当时。
定义 C
时有两个选项,具体取决于您是否要定义 C.__init__
并在签名中提及 A
和 B
所需的两个参数初始化。对于 C1
,C1.__init__
未定义,因此将调用 A.__init__
。使用 C2
,您需要显式调用链中的下一个 __init__
方法。
C
,知道它是 A
和 B
的子 class,必须至少为已知的上游 [=24] 提供预期的参数=] 方法。
A.__init__
将传递所有 除了 a
到下一个 class 的 __init__
方法。
B.__init__
将传递 它 收到的所有内容,除了 b
.
object.__init__
最终将被调用,并且假设所有先前的 classes 都正确删除了它们引入的关键字参数,将不会收到额外的参数。
更改调用各种 __init__
的顺序意味着更改 MRO,这意味着更改基础 class 的顺序。如果你想要更多的控制权,那么合作多重继承不适合你。
对于最基本的多重继承的情况:
class A:
def __init__(self, a):
self.a = a
class B:
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
我不明白为什么要使用 super()
。我想你可以用 kwargs 来实现它,但这肯定不如上面的方法可读。我还没有找到任何支持这种方法的堆栈溢出答案,但对于这种情况,它肯定是最令人满意的吗?
有很多关于这个主题的问题被标记为重复,但对于这个确切的案例没有令人满意的答案。 super()
for a diamond inheritance. In this case there is no diamond inheritance and neither parent class have any knowledge of each other, so they shouldn't need to call super()
like
This answer deals with the use of super
in this scenario but without passing arguments to __init__
like is done here, and this answer 处理传递参数,但又是钻石继承。
class A(object):
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
self.a = kwargs['a']
class B(object):
def __init__(self, *args, **kwargs):
super(B, self).__init__()
self.b = kwargs['b']
class C(A, B):
def __init__(self, *args, **kwargs):
super(C, self).__init__(*args, **kwargs)
z = C(a=1,b=2)
z.b
2
此处使用 super
的一种正确方法是
class A:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
self.a = a
class B:
def __init__(self, b, **kwargs):
super().__init__(**kwargs)
self.b = b
class C1(A, B):
pass
class C2(A, B):
def __init__(self, a, b, **kwargs):
super().__init__(a=a, b=b, **kwargs)
c1 = C1(a="foo", b="bar")
c2 = C2(a="foo", b="bar")
C
的方法解析顺序是 [C, A, B, object]
。每次调用 super()
时,它 returns 是 MRO 中 next class 的代理,基于调用 super()
的位置当时。
定义 C
时有两个选项,具体取决于您是否要定义 C.__init__
并在签名中提及 A
和 B
所需的两个参数初始化。对于 C1
,C1.__init__
未定义,因此将调用 A.__init__
。使用 C2
,您需要显式调用链中的下一个 __init__
方法。
C
,知道它是 A
和 B
的子 class,必须至少为已知的上游 [=24] 提供预期的参数=] 方法。
A.__init__
将传递所有 除了 a
到下一个 class 的 __init__
方法。
B.__init__
将传递 它 收到的所有内容,除了 b
.
object.__init__
最终将被调用,并且假设所有先前的 classes 都正确删除了它们引入的关键字参数,将不会收到额外的参数。
更改调用各种 __init__
的顺序意味着更改 MRO,这意味着更改基础 class 的顺序。如果你想要更多的控制权,那么合作多重继承不适合你。