pythonsuper多重继承_Python多重继承引发的问题——牛逼的super

少说废话多做事先上一个图,此图用win7下的画图工具所画,当然,这不是重点

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

需要清楚的一个事情是:

任何类,都默认并隐式的继承object类(根类),在上面的图中,Transformers类同时继承了Car和Ship类。那么Car和Ship又隐式的继承了object类,注意,这个object类不是我自己定义的

而是python的。

根据上面的图,编写代码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类被隐式的调用了两次,只是目前没有察觉到,但是确实存在。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

OK!!!我想证明这个问题,证实它是不是被调用两次。我再上一个图,如下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上面的图,就是传说中的砖石继承,啥是砖石继承?只是这个类的继承视图看起来和砖石一样,当然这只是我的理解。

如果用这个图来证明BaseClass会不会被调用2次,那么需要转化成代码。代码如下: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,我不信,所以我尝试了一下,改进后的代码如下: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的威力。然而,不管你信不信,反正我是信了。

那分析一下他的调用顺序,我又画了个图:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=看图分析: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去做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

改进后的代码如下: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是绝对的保证,在类的继承层次结构中每一个方法只被执行一次

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值