python 使用 super 向构造函数传递参数的多重继承
python multiple inheritance passing arguments to constructors using super
考虑以下 python 代码片段
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super(B, self).__init__(a)
self.b = b
class C(A):
def __init__(self, a, c):
super(C, self).__init__(a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
#super(D,self).__init__(a, b, c) ???
self.d = d
我想知道如何将 a
、b
和 c
传递给相应的基础 类' 构造函数。
不幸的是,如果不更改 Base classes,就无法使用 super()
来完成这项工作。对 B
或 C
的构造函数的任何调用都将尝试调用 Method Resolution Order 中的下一个 class,它将始终是 B
或 C
而不是 B
和 C
class 构造函数假定的 A
class。
另一种方法是在每个 class.
中显式调用构造函数而不使用 super()
class A(object):
def __init__(self, a):
object.__init__()
self.a = a
class B(A):
def __init__(self, a, b):
A.__init__(self, a)
self.b = b
class C(A):
def __init__(self, a, c):
A.__init__(self, a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
B.__init__(self, a, b)
C.__init__(self, a, c)
self.d = d
这里还有一个缺点,因为 A
构造函数会被调用两次,这在这个例子中并没有太大的影响,但在更复杂的构造函数中可能会导致问题。您可以包含一个检查以防止构造函数 运行 不止一次。
class A(object):
def __init__(self, a):
if hasattr(self, 'a'):
return
# Normal constructor.
有些人会说这是super()
的缺点,从某种意义上说,这也是多重继承的缺点。菱形继承模式往往容易出错。并且许多针对它们的解决方法会导致更加混乱和 error-prone 代码。有时,最好的答案是尝试重构您的代码以使用更少的多重继承。
好吧,在处理一般的多重继承时,您的基础 类(不幸的是)应该设计用于多重继承。 类 B
和 C
在你的例子中不是,因此你找不到在 D
.[=17 中应用 super
的正确方法=]
为多重继承设计基础 类 的一种常见方法是让 middle-level 基础 类 在其 __init__
方法中接受额外的参数,他们不打算使用的,并将它们传递给他们的 super
调用。
这是 python 中的一种方法:
class A(object):
def __init__(self,a):
self.a=a
class B(A):
def __init__(self,b,**kw):
self.b=b
super(B,self).__init__(**kw)
class C(A):
def __init__(self,c,**kw):
self.c=c
super(C,self).__init__(**kw)
class D(B,C):
def __init__(self,a,b,c,d):
super(D,self).__init__(a=a,b=b,c=c)
self.d=d
这可以被视为令人失望,但事实就是如此。
我对这里的答案并不完全满意,因为有时使用不同的参数分别为每个基 类 调用 super() 而不重构它们会变得非常方便。因此,我创建了一个名为 multinherit 的包,您可以使用该包轻松解决这个问题。 https://github.com/DovaX/multinherit
from multinherit.multinherit import multi_super
class A(object):
def __init__(self, a):
self.a = a
print(self.a)
class B(A):
def __init__(self, a, b):
multi_super(A,self,a=a)
self.b = b
print(self.b)
class C(A):
def __init__(self, a, c):
multi_super(A,self,a=a)
self.c = c
print(self.c)
class D(B, C):
def __init__(self, a, b, c, d):
multi_super(B,self,a=a,b=b)
multi_super(C,self,a=a,c=c)
self.d = d
print(self.d)
print()
print("d3")
d3=D(1,2,3,4)
print(d3._classes_initialized)
>>> d3
>>> 1
>>> 2
>>> 3
>>> 4
>>> [<class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>]
一个key概念:super不指parentclass。它指的是mro列表中的下一个class,这取决于实际实例化的class。
所以当调用super().__init__
时,调用的实际方法未从调用框架中确定。
这就是 classes 必须专门为 mixin 设计的原因。
即使 class 仅继承自 object
,也应调用 super().__init__
。
当然,当 object__init__(**kwargs)
被调用时, kwargs
应该是空的;否则会引发错误。
示例:
class AMix:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
self.a = a
class BMix:
def __init__(self, b, **kwargs):
super().__init__(**kwargs)
self.b = b
class AB(AMix, BMix):
def __init__(self, a, b):
super().__init__(a=a, b=b)
ab = AB('a1', 'b2')
print(ab.a, ab.b) # -> a1 b2
考虑以下 python 代码片段
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super(B, self).__init__(a)
self.b = b
class C(A):
def __init__(self, a, c):
super(C, self).__init__(a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
#super(D,self).__init__(a, b, c) ???
self.d = d
我想知道如何将 a
、b
和 c
传递给相应的基础 类' 构造函数。
不幸的是,如果不更改 Base classes,就无法使用 super()
来完成这项工作。对 B
或 C
的构造函数的任何调用都将尝试调用 Method Resolution Order 中的下一个 class,它将始终是 B
或 C
而不是 B
和 C
class 构造函数假定的 A
class。
另一种方法是在每个 class.
中显式调用构造函数而不使用super()
class A(object):
def __init__(self, a):
object.__init__()
self.a = a
class B(A):
def __init__(self, a, b):
A.__init__(self, a)
self.b = b
class C(A):
def __init__(self, a, c):
A.__init__(self, a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
B.__init__(self, a, b)
C.__init__(self, a, c)
self.d = d
这里还有一个缺点,因为 A
构造函数会被调用两次,这在这个例子中并没有太大的影响,但在更复杂的构造函数中可能会导致问题。您可以包含一个检查以防止构造函数 运行 不止一次。
class A(object):
def __init__(self, a):
if hasattr(self, 'a'):
return
# Normal constructor.
有些人会说这是super()
的缺点,从某种意义上说,这也是多重继承的缺点。菱形继承模式往往容易出错。并且许多针对它们的解决方法会导致更加混乱和 error-prone 代码。有时,最好的答案是尝试重构您的代码以使用更少的多重继承。
好吧,在处理一般的多重继承时,您的基础 类(不幸的是)应该设计用于多重继承。 类 B
和 C
在你的例子中不是,因此你找不到在 D
.[=17 中应用 super
的正确方法=]
为多重继承设计基础 类 的一种常见方法是让 middle-level 基础 类 在其 __init__
方法中接受额外的参数,他们不打算使用的,并将它们传递给他们的 super
调用。
这是 python 中的一种方法:
class A(object):
def __init__(self,a):
self.a=a
class B(A):
def __init__(self,b,**kw):
self.b=b
super(B,self).__init__(**kw)
class C(A):
def __init__(self,c,**kw):
self.c=c
super(C,self).__init__(**kw)
class D(B,C):
def __init__(self,a,b,c,d):
super(D,self).__init__(a=a,b=b,c=c)
self.d=d
这可以被视为令人失望,但事实就是如此。
我对这里的答案并不完全满意,因为有时使用不同的参数分别为每个基 类 调用 super() 而不重构它们会变得非常方便。因此,我创建了一个名为 multinherit 的包,您可以使用该包轻松解决这个问题。 https://github.com/DovaX/multinherit
from multinherit.multinherit import multi_super
class A(object):
def __init__(self, a):
self.a = a
print(self.a)
class B(A):
def __init__(self, a, b):
multi_super(A,self,a=a)
self.b = b
print(self.b)
class C(A):
def __init__(self, a, c):
multi_super(A,self,a=a)
self.c = c
print(self.c)
class D(B, C):
def __init__(self, a, b, c, d):
multi_super(B,self,a=a,b=b)
multi_super(C,self,a=a,c=c)
self.d = d
print(self.d)
print()
print("d3")
d3=D(1,2,3,4)
print(d3._classes_initialized)
>>> d3
>>> 1
>>> 2
>>> 3
>>> 4
>>> [<class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>]
一个key概念:super不指parentclass。它指的是mro列表中的下一个class,这取决于实际实例化的class。
所以当调用super().__init__
时,调用的实际方法未从调用框架中确定。
这就是 classes 必须专门为 mixin 设计的原因。
即使 class 仅继承自 object
,也应调用 super().__init__
。
当然,当 object__init__(**kwargs)
被调用时, kwargs
应该是空的;否则会引发错误。
示例:
class AMix:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
self.a = a
class BMix:
def __init__(self, b, **kwargs):
super().__init__(**kwargs)
self.b = b
class AB(AMix, BMix):
def __init__(self, a, b):
super().__init__(a=a, b=b)
ab = AB('a1', 'b2')
print(ab.a, ab.b) # -> a1 b2