Super可以处理多重继承吗?

时间:2011-10-26 13:36:36

标签: python multiple-inheritance

从这样的两个对象继承时

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)

超级怎么知道我是否想要同时打电话?如果是这样,它将如何知道哪个参数传递到哪里。或者根本不可能在这里使用超级?

即使Foo和Bar采用相同的参数,super可以解决这个问题吗?

或者我不应该首先尝试这样做吗?

2 个答案:

答案 0 :(得分:7)

使用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__(),因为该调用可能由{{1}处理}。但是它可能object.__init__处理,而是由继承图中的其他类处理。因此,任何类在多继承类层次结构中定义object.__init__必须准备好用无参数调用。

解决这个问题的一种方法是永远不要在__init__中使用参数。进行最小化初始化,并依赖于设置属性或使用其他方法在使用前配置新对象。不过,这真是令人不愉快。

另一种方法是仅使用关键字参数,例如__init__(),并始终删除适用于给定构造函数的参数。这是一个基于希望的策略,您希望在控制达到def __init__(self, **keywords):之前所有关键字都被消耗。

第三种方法是为所有多重可继承的基础定义一个超类,它本身以某种有用的方式定义object.__init__并且调用__init__({{ 1}}无论如何都是无操作的)。这意味着你可以确定这个方法总是最后调用,你可以随意使用你的参数。

答案 1 :(得分:2)

  

或者我不应该首先尝试这样做吗?

正确。您应该只调用__init__的一个父行,而不是树。 super将使用MRO对父类进行深度优先搜索,以查找要调用的正确__init__。它不会也不应该调用所有可能的__init__