super()
没有被破坏——它只是不应该被认为是调用基类方法的标准方式。这在 Python 3.x 中没有改变。唯一改变的是您不需要self, cls
在标准情况下传递参数,这self
是当前函数的第一个参数并且cls
是当前正在定义的类。
关于您何时实际使用的问题super()
,我的回答是:几乎没有。我个人尽量避免那种super()
有用的多重继承。
编辑:我曾经遇到的现实生活中的一个例子:我有一些定义run()
方法的类,其中一些有基类。我曾经super()
调用继承的构造函数——我认为这并不重要,因为我只使用单继承:
class A(object):
def __init__(self, i):
self.i = i
def run(self, value):
return self.i * value
class B(A):
def __init__(self, i, j):
super(B, self).__init__(i)
self.j = j
def run(self, value):
return super(B, self).run(value) + self.j
试想一下,有几个这样的类,都具有单独的构造函数原型,并且都具有相同的run()
.
现在我想为所有这些类添加一些额外的功能,比如日志记录。附加功能需要在所有这些类上定义一个附加方法,例如info()
. 我不想侵入原始类,而是定义了第二组从原始类继承的类,添加info()
方法并从提供实际日志记录的混合中继承。现在,我不能再super()
在构造函数中使用了,所以我使用了直接调用:
class Logger(object):
def __init__(self, name):
self.name = name
def run_logged(self, value):
print "Running", self.name, "with info", self.info()
return self.run(value)
class BLogged(B, Logger):
def __init__(self, i, j):
B.__init__(self, i, j)
Logger.__init__("B")
def info(self):
return 42
事情在这里停止工作。基类构造函数中的super()
调用突然调用Logger.__init__()
,BLogged
对此无能为力。实际上没有办法使这项工作,除了删除super()
调用B
本身。
[另一个编辑:从这里和其他答案下方的所有评论来看,我似乎没有表达我的观点。以下是如何使用以下代码使此代码工作super()
:
class A(object):
def __init__(self, i, **kwargs):
super(A, self).__init__(**kwargs)
self.i = i
def run(self, value):
return self.i * value
class B(A):
def __init__(self, j, **kwargs):
super(B, self).__init__(**kwargs)
self.j = j
def run(self, value):
return super(B, self).run(value) + self.j
class Logger(object):
def __init__(self, name, **kwargs):
super(Logger,self).__init__(**kwargs)
self.name = name
def run_logged(self, value):
print "Running", self.name, "with info", self.info()
return self.run(value)
class BLogged(B, Logger):
def __init__(self, **kwargs):
super(BLogged, self).__init__(name="B", **kwargs)
def info(self):
return 42
b = BLogged(i=3, j=4)
将此与使用显式超类调用进行比较。你决定你喜欢哪个版本。]
这个和类似的故事是为什么我认为super()
不应将其视为调用基类方法的标准方式。这并不意味着super()
坏了。