Python中子类要调用父类的方法(method),在python2.2之前通常的写法如下:

1
2
3
4
5
6
7
8
9
10
class A():
def __inti__(self):
print "enter A"
print "leave A"

class B():
def __init__(self):
print "enter B"
A.__init__(self)
print "leave B"

即使用非绑定的类方法(用类名来引用),并在参数列表中引入待绑定的对象(self),从而达到调用父类的目的。这样做的缺点是,当一个子类的父类发生变化时(如类B的父类由A变为C时),必须遍历整个类定义,把所有的通过非绑定的方法的类名全部替换过来。

自python2.2开始,python添加了一个关键字super来解决这个问题。官方说明如下:

super(type[, object-or-type])

Return the superclass of type. If the second argument is omitted the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true. super() only works for new-style classes.

A typical use for calling a cooperative superclass method is:

1
2
3
class C(B):
def meth(self, arg):
super(C, self).meth(arg)

New in version 2.2.

因此改写后的类B代码如下:

1
2
3
4
5
6
7
8
9
10
class A(object):    # A must be new-style class
def __init__(self):
print "enter A"
print "leave A"

class B(C): # A --> C
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"

其运行结果与第一种方法一致。


super的引入同时也解决了涉及多继承情况时父类的多次调用问题,考虑如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class A():
def __init__(self):
print "Enter A"
print "Leave A"

class B(A):
def __init__(self):
print "Enter B"
A.__init__(self)
print "Leave B"

class C(A):
def __init__(self):
print "Enter C"
A.__init__(self)
print "Leave C"

class D(A):
def __init__(self):
print "Enter D"
A.__init__(self)
print "Leave D"

class E(B, C, D):
def __init__(self):
print "Enter E"
B.__init__(self)
C.__init__(self)
D.__init__(self)
print "Leave E"

e = E()

结果如下:

1
Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E

其中公共父类A被执行了多次。 将其中的类名引用换为super:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class A():
def __init__(self):
print "Enter A"
print "Leave A"

class B(A):
def __init__(self):
print "Enter B"
super(B, self)__init__()
print "Leave B"

class C(A):
def __init__(self):
print "Enter C"
super(C, self)__init__()
print "Leave C"

class D(A):
def __init__(self):
print "Enter D"
super(D, self)__init__()
print "Leave D"

class E(B, C, D):
def __init__(self):
print "Enter E"
super(E, self)__init__()
print "Leave E"

e = E()

执行结果如下:

1
Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E

在super机制中能够保证公共父类仅被执行一次,且执行的顺序按照MRO进行(E.__mro__)。


super在使用中有下列需要注意的地方:

  1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,产生了一个super对象;
  2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
  3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
  4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super);
  5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次。

参考资料:

  1. Python 中的super用法详解
  2. 关于Python的super用法研究