我想了解 Python 中的 MRO。虽然这里有各种各样的帖子,但我并没有特别得到我想要的。考虑从 BaseClass
派生的两个类 A
和 B
,每个类都有一个采用不同参数的 __init__
。
class BaseClass(object):
def __init__(self):
print "I am the base class"
class A(BaseClass):
def __init__(self, something, anotherthing):
super(A, self).__init__()
self.something = something
self.anotherthing = anotherthing
def methodsA(self):
...
class B(BaseClass):
def __init__(self, someOtherThing):
super(B, self).__init__()
self.someOtherThing = someOtherThing
def methodsB(self):
...
问题是,如果我需要从 A
和 B
派生第三类 C
,我该如何初始化 __init__
,如果必须的话?我可以安全地从 B
或 A
派生 C
。
class C(A,B):
def __init__(self, something, anotherthing, someOtherThing):
super(C, self).__init__(something, anotherthing, someOtherThing)
上面的实现给我一个错误。
最佳答案
正如 jonrsharpe 在他的帖子末尾提到的,这是我遇到的最好的方式
处理这种情况的方法是接受 **kwargs
并提取
显式命名参数。
class BaseClass(object):
def __init__(self, **kwargs):
print("BaseClass.__init__({},{})".format('', kwargs))
super(BaseClass,self).__init__(**kwargs)
class A(BaseClass):
def __init__(self, **kwargs):
print("A.__init__({},{})".format('', kwargs))
a = kwargs.pop('something')
super(A,self).__init__(**kwargs)
class B(BaseClass):
def __init__(self, **kwargs):
print("B.__init__({},{})".format('', kwargs))
b = kwargs.pop('anotherthing')
super(B,self).__init__(**kwargs)
class C(A, B):
def __init__(self, **kwargs):
print("C.__init__({},{})".format('', kwargs))
super(C,self).__init__(**kwargs)
c = C(something=1,anotherthing='a')
需要提取的参数应该以命名方式传递,所以它们出现在kwargs中。
您甚至可以像示例中一样通过省略 *args
来显式仅接受命名参数,因此如果您忘记了,就会遇到 TypeError。
编辑:
经过一段时间的思考,我意识到我的示例非常适合您的示例,如果您引入另一个类或更改继承,它可能会中断。有两件事应该解决以使其更通用:
BaseClass 不调用 super。
对于示例,这无关紧要,但如果引入了另一个类,则 MRO 可能会更改,以便在 BaseClass 之后有一个类,因此它应该调用 super。这就引出了第二个问题:
object.__init__()
不带参数
如果我们想让类(特别是 BaseClass)安全地放入一个通用的多重继承结构中,在这个结构中它的 super 调用可能被分派(dispatch)到另一个类 或 对象,我们需要从 kwargs 中弹出参数当我们消费它们时。
但这增加了另一个复杂性,因为它要求没有两个 __init__
函数共享相同的参数名称。我想得出的结论是让多重继承以一种通用的方式工作是很困难的。
这是一篇关于一些细节的有趣文章(通过谷歌找到):article
关于python - 具有不同初始化参数的基类的方法解析顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21862357/