super 是一个内置类,可用于访问属于某个对象的超类的属性。

如果你已经习惯于通过直接调用父类并传入 self 作为第一个参数来访问类的属性或

方法,那么 super 的用法会有些令人困惑。这是非常陈旧的模式,但仍然可以在一些代码

库中找到(特别是遗留项目)。参见以下代码:

class Mama: # 旧的写法

def says(self):

print('do your homework')

class Sister(Mama):

def says(self):

Mama.says(self)

print('and clean your bedroom')

在解释器会话中运行,它会给出如下结果:

>>> Sister().says()

do your homework

and clean your bedroom

重点看一下 Mama.says(self)这一行,这里我们使用刚刚提到的方法来调用超类

(即 Mama 类)的 says()方法,并将 self 作为参数传入。也就是说,调用的是属于 Mama

的 says()方法。但它的作用对象由 self 参数给出,在这个例子中是一个 Sister 实例。

而 super 的用法如下所示:

class Sister(Mama):

def says(self):

super(Sister, self).says()

print('and clean your bedroom')

或者,你也可以使用 super()调用的简化形式如下:

class Sister(Mama):

def says(self):

super().says()

print('and clean your bedroom')

super 的简化形式(不传入任何参数)可以在方法内部使用,但 super 的使用并不

限于方法。在代码中需要调用给定实例的超类方法的任何地方都可以使用它。不过,如果

super 不在方法内部使用,那么必须给出如下参数:

>>> anita = Sister()

>>> super(anita.__class__, anita).says()

do your homework

最后,关于 super 还有很重要的一点需要注意,就是它的第二个参数是可选的。如果

只提供了第一个参数,那么 super 返回的是一个未绑定(unbound)类型。这一点在与

classmethod 一起使用时特别有用,如下所示:

class Pizza:

def __init__(self, toppings):

self.toppings = toppings

def __repr__(self):

return "Pizza with " + " and ".join(self.toppings)

@classmethod

def recommend(cls):

"""推荐任意馅料(toppings)的某种披萨。"""

return cls(['spam', 'ham', 'eggs'])

class VikingPizza(Pizza):

@classmethod

def recommend(cls):

"""推荐与 super 相同的内容,但多加了午餐肉(spam)。"""

recommended = super(VikingPizza).recommend()

recommended.toppings += ['spam'] * 5

return recommended

注意,零参数的 super()形式也可用于被 classmethod 装饰器装饰的方法。在这样

的方法中无参数调用的 super()被看作是仅定义了第一个参数。

前面提到的使用实例很容易理解,但如果面对多重继承模式,super 将变得难以使用。

在解释这些问题之前,理解何时应避免使用 super 以及方法解析顺序(Method Resolution

Order,MRO)在 Python 中的工作原理是很重要的。

Python 2 中的旧式类与 super

Python 2 中 super()的工作原理几乎完全相同。调用签名的唯一区别在于简化的零参

数形式不可用,因此必须始终提供至少一个参数。

对于想要编写跨版本兼容的代码的程序员来说,另一件重要的事情是,Python 2 中的

super 只适用于新式类。在早期版本的 Python 中,所有类并没有一个共同的祖先 object。

Python 所有的 2.x 版本中都保留了旧式类,目的是为了向后兼容,所以在这些版本中,如

果类的定义中没有指定祖先,那么它就被解释为旧式类,且不能使用 super,如下所示:

class OldStyle1:

pass

class OldStyle2():

pass

Python 2 中的新式类必须显式继承 object 或其他新式类:

class NewStyleClass(object):

pass

class NewStyleClassToo(NewStyleClass):

pass

Python 3 不再保留旧式类的概念,因此,没有继承任何其他类的类都隐式地继承自

object。也就是说,显式声明某个类继承自 object 似乎是冗余的。通用的良好实践是

不包括冗余代码。但在这个例子中,只有该项目不再用于任何 Python 2 版本时,删除这些

冗余才是好的做法。如果代码想要保持 Python 的跨版本兼容,那么必须始终将 object 作

为所有基类的祖先,即使这在 Python 3 中是冗余的。不这么做的话,这些类将被解释为旧

式类,最终会导致难以诊断的问题。