少说废话多做事先上一个图,此图用win7下的画图工具所画,当然,这不是重点
需要清楚的一个事情是:
任何类,都默认并隐式的继承object类(根类),在上面的图中,Transformers类同时继承了Car和Ship类。那么Car和Ship又隐式的继承了object类,注意,这个object类不是我自己定义的
而是python的。
根据上面的图,编写代码
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
class
Car:
#描述汽车
call_car_record
=
0
#记录调用次数
def
__init__(
self
, car_name):
self
.car_name
=
car_name
def
land_run(
self
):
print
(
"{0} Run on land"
.
format
(
self
.car_name))
self
.call_car_record
+
=
1
class
Ship:
#描述轮船
call_ship_record
=
0
#记录调用次数
def
__init__(
self
, ship_name):
self
.ship_name
=
ship_name
def
running_in_sea(
self
):
print
(
"{0} Running in the sea"
.
format
(
self
.ship_name))
self
.call_ship_record
+
=
1
class
Transformers(Car, Ship):
#变形金刚
call_tran_record
=
0
#记录调用次数
def
__init__(
self
, car_name, ship_name, tran_name):
Car.__init__(
self
, car_name)
Ship.__init__(
self
, ship_name)
self
.tran_name
=
tran_name
def
transfiguration(
self
):
print
(
"{0} start Transfiguration..."
.
format
(
self
.tran_name))
self
.call_tran_record
+
=
1
if
__name__
=
=
'__main__'
:
t
=
Transformers(
"byd"
,
"gz01"
,
"toby"
)
t.land_run()
t.running_in_sea()
t.transfiguration()
print
(t.call_tran_record, t.call_car_record, t.call_ship_record)
"""
输出的结果:
byd Run on land
gz01 Running in the sea
toby start Transfiguration...
1 1 1
"""
|
那么,上面的代码,面临的问题正是我在上图中的描述,也就是说object类被隐式的调用了两次,只是目前没有察觉到,但是确实存在。
OK!!!我想证明这个问题,证实它是不是被调用两次。我再上一个图,如下:
上面的图,就是传说中的砖石继承,啥是砖石继承?只是这个类的继承视图看起来和砖石一样,当然这只是我的理解。
如果用这个图来证明BaseClass会不会被调用2次,那么需要转化成代码。代码如下:
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
33
34
35
36
37
38
39
40
41
42
43
44
|
class
BaseClass:
num_base_calls
=
0
#记录基类被调用次数
def
work(
self
):
print
(
"work method of calling base class"
)
self
.num_base_calls
+
=
1
class
AClass(BaseClass):
num_aclass_calls
=
0
#记录被调用次数
def
work(
self
):
BaseClass.work(
self
)
print
(
"work method of calling AClass class"
)
self
.num_aclass_calls
+
=
1
class
BClass(BaseClass):
num_bclass_calls
=
0
#记录被调用次数
def
work(
self
):
BaseClass.work(
self
)
print
(
"work method of calling BClass class"
)
self
.num_bclass_calls
+
=
1
class
CClass(AClass, BClass):
num_cclass_calls
=
0
#记录被调用次数
def
work(
self
):
AClass.work(
self
)
BClass.work(
self
)
print
(
"Calling work method on CClass"
)
self
.num_cclass_calls
+
=
1
if
__name__
=
=
'__main__'
:
c
=
CClass()
c.work()
print
(c.num_cclass_calls, c.num_aclass_calls, c.num_bclass_calls, c.num_base_calls)
"""
结果输出:
work method of calling base class
work method of calling AClass class
work method of calling base class
work method of calling BClass class
Calling work method on CClass
1 1 1 2
"""
|
从输出的结果来看,BaseClass真的被调用了两次,这个基类是我自己定义的,这不是隐式调用,是明目张胆的在调用啊!!!
如何解决这个问题?专业人士说用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
33
34
35
36
37
38
39
|
class
BaseClass:
num_base_calls
=
0
#记录基类被调用次数
def
work(
self
):
print
(
"work method of calling base class"
)
self
.num_base_calls
+
=
1
class
AClass(BaseClass):
num_aclass_calls
=
0
#记录被调用次数
def
work(
self
):
super
().work()
print
(
"work method of calling AClass class"
)
self
.num_aclass_calls
+
=
1
class
BClass(BaseClass):
num_bclass_calls
=
0
#记录被调用次数
def
work(
self
):
super
().work()
print
(
"work method of calling BClass class"
)
self
.num_bclass_calls
+
=
1
class
CClass(AClass, BClass):
num_cclass_calls
=
0
#记录被调用次数
def
work(
self
):
super
().work()
print
(
"Calling work method on CClass"
)
self
.num_cclass_calls
+
=
1
if
__name__
=
=
'__main__'
:
c
=
CClass()
c.work()
print
(c.num_cclass_calls, c.num_aclass_calls, c.num_bclass_calls, c.num_base_calls)
"""
输出结果:
work method of calling base class
work method of calling BClass class
work method of calling AClass class
Calling work method on CClass
1 1 1 1
"""
|
事实证明,BaseClass这个基类真的只被调用了一次,这就是super的威力。然而,不管你信不信,反正我是信了。
那分析一下他的调用顺序,我又画了个图:
看图分析:
1、CClass类的work()方法调用了super.work,其实是引用了AClass.work()
2、在AClass.work()中,调用了super.work(),这时候是引用了BClass.work(),而不是BaseClass.work(),这就是所谓的下一个方法
3、接着在BClass.work()中调用了super.work()方法,这时候才是去调用BaseClass.work()方法
现在回到第一个多重继承的例子,在多重继承的例子中,Transformers类的__init__方法中,为了实现能调用两个父类的__init__()方法
我最初的做法是,分别写了两次调用。这里面临的问题是,有两个父类的初始化方法要调用,而且还是需要不同的参数。
那么,我一开始就写成如下面代码这样,不是不行,而是不是我追求的目标,我是一个追求完美的人,所以我决定改进它,也是用super去做
1
2
3
4
5
6
7
|
class
Transformers(Car, Ship):
#变形金刚
call_tran_record
=
0
def
__init__(
self
, car_name, ship_name, tran_name):
Car.__init__(
self
, car_name)
#调用Car类的初始化方法
Ship.__init__(
self
, ship_name)
#调用Ship类的初始化方法
self
.tran_name
=
tran_name
|
改进后的代码如下:
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
33
34
35
36
37
38
39
40
|
class
Car:
#描述汽车
call_car_record
=
0
#记录调用次数
def
__init__(
self
, car_name
=
None
,
*
*
kwargs):
super
().__init__(
*
*
kwargs)
self
.car_name
=
car_name
def
land_run(
self
):
print
(
"{0} Run on land"
.
format
(
self
.car_name))
self
.call_car_record
+
=
1
class
Ship:
#描述轮船
call_ship_record
=
0
#记录调用次数
def
__init__(
self
, ship_name
=
None
,
*
*
kwargs):
super
().__init__(
*
*
kwargs)
self
.ship_name
=
ship_name
def
running_in_sea(
self
):
print
(
"{0} Running in the sea"
.
format
(
self
.ship_name))
self
.call_ship_record
+
=
1
class
Transformers(Car, Ship):
#变形金刚
call_tran_record
=
0
#记录调用次数
def
__init__(
self
, tran_name
=
None
,
*
*
kwargs):
super
().__init__(
*
*
kwargs)
self
.tran_name
=
tran_name
def
transfiguration(
self
):
print
(
"{0} start Transfiguration..."
.
format
(
self
.tran_name))
self
.call_tran_record
+
=
1
if
__name__
=
=
'__main__'
:
t
=
Transformers(tran_name
=
"toby"
, car_name
=
"byd"
, ship_name
=
"qq"
)
t.land_run()
t.running_in_sea()
t.transfiguration()
print
(t.call_tran_record, t.call_car_record, t.call_ship_record)
|
关于如何分析它的执行顺序?请用“下一个方法”的思路去理解它。
最后,再总结一下super的牛逼之处
1、在类的继承层次结构中,只想调用"下一个方法",而不是父类的方法
2、super的目标就是解决复杂的多重继承问题(基类被调用两次的问题)
3、super是绝对的保证,在类的继承层次结构中每一个方法只被执行一次
本文转自 TtrToby 51CTO博客,原文链接:http://blog.51cto.com/freshair/2063290