Super 可以处理多重继承吗?
当从两个对象继承时,比如这样
class Foo(object):
def __init__(self,a):
self.a=a
class Bar(object):
def __init__(self,b):
self.b=b
我通常会这样做
class FooBar(Foo,Bar):
def __init__(self,a,b):
Foo.__init__(self,a)
Bar.__init__(self,b)
那这个 super 是怎么知道我想同时调用两个的呢?如果是的话,它又怎么知道该把哪个参数传给哪个呢?或者说在这种情况下根本就不能使用 super?
即使 Foo 和 Bar 接受相同的参数,super
能处理这种情况吗?
还是说我根本就不应该尝试这样做?
2 个回答
我是不是根本就不应该尝试做这种事情呢?
没错。你应该只调用一个父类的 __init__
方法,而不是所有的父类。super
会根据方法解析顺序(MRO)来进行深度优先搜索,找到合适的 __init__
方法来调用。它不会也不应该调用所有可能的 __init__
方法。
使用 super()
、__init__()
和多重继承有点复杂。
在正常情况下,每个方法都会调用 super()
,而那些只继承自 object
的类会做一些额外的工作,以确保这个方法确实存在:看起来大概是这样的:
>>> class Foo(object):
... def frob(self, arg):
... print "Foo.frob"
... if hasattr(super(Foo, self), 'frob'):
... super(Foo, self).frob(arg)
...
>>> class Bar(object):
... def frob(self, arg):
... print "Bar.frob"
... if hasattr(super(Bar, self), 'frob'):
... super(Bar, self).frob(arg)
...
>>> class Baz(Foo, Bar):
... def frob(self, arg):
... print "Baz.frob"
... super(Baz, self).frob(arg)
...
>>> b = Baz()
>>> b.frob(1)
Baz.frob
Foo.frob
Bar.frob
>>>
但是当你尝试在 object
实际上已经有的方法上做类似的事情时,情况就有点棘手了;因为 object.__init__
不接受任何参数,所以安全的做法就是调用 super().__init__()
而不传参数,因为这个调用 可能 会被 object.__init__
处理。但也有可能 不会 被 object.__init__
处理,而是被继承图中其他的某个类处理。因此,任何 在多重继承类层次中定义了 __init__
的类都必须准备好接受 没有参数 的调用。
处理这个问题的一种方法是,在 __init__()
中从不使用参数。只做最基本的初始化,然后依靠设置属性或其他方式在使用之前配置新对象。不过,这样做其实挺麻烦的。
另一种方法是只使用关键字参数,比如 def __init__(self, **keywords):
,并始终移除适用于当前构造函数的参数。这是一种基于希望的策略,你 希望 所有的关键字参数在控制权到达 object.__init__
之前都能被处理掉。
第三种方法是定义一个所有可多重继承基类的超类,这个超类以某种有用的方式定义了 __init__
,并且 不 调用 super().__init__
(因为 object.__init__
本身是个空操作)。这样你就可以 确保 这个方法总是最后被调用,你可以随意处理你的参数。