Python菱形继承的初始化问题和继承顺序
Posted 小斌哥ge
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python菱形继承的初始化问题和继承顺序相关的知识,希望对你有一定的参考价值。
Python菱形继承的初始化问题和继承顺序
Python中,类通过继承的方式,子类可以获得父类的非私有属性和非私有方法,不需要自己再重新实现。
继承可以多层继承,即可以多代继承。也可以多继承,即一个子类可以继承多个父类。
一、菱形继承简介
在多层继承和多继承同时使用的情况下,就会出现复杂的继承关系,多重多继承。
其中,就会出现菱形继承。如下图所示。
菱形继承也叫钻石继承,在这种结构中,当D类的对象使用一个属性时,首先会在D类中查找是否有该属性和方法,如果没有则会到父类中查找,如果还没有则会继续往父类的父类中查找。
根据这种关系,如果D类中没有找到属性和方法,是去B类中查找还是去C类中查找?
假设是去B类中查找,如果B类中也没有找到,下一步是去C类中还是A类中呢?
这些问题都是菱形继承所带来的问题,接下来我们来看Python中是怎么处理的。
二、菱形继承的初始化问题
class Electrical(object):
def __init__(self, name):
self.name = name
print(Electrical init)
class Phone(Electrical):
def __init__(self, name, price):
Electrical.__init__(self, name)
self.price = price
print(Phone init)
class Computer(Electrical):
def __init__(self, name, config):
Electrical.__init__(self, name)
self.config = config
print(Computer init)
class HuaWei(Phone, Computer):
def __init__(self, name, price, config):
Phone.__init__(self, name, price)
Computer.__init__(self, name, config)
print(HuaWei init)
h = HuaWei(huawei, 100, i7)
运行结果:
Electrical init
Phone init
Electrical init
Computer init
HuaWei init
上面的Phone类和Computer类都继承了Electrical类,HuaWei类既继承了Phone类又继承了Computer类,这就形成了一个菱形的继承关系。
在创建HuaWei类对象时,Electrical类的__init__方法执行了两遍,也就是说在Phone类向上继承时执行了,在Computer类向上继承时也执行了,这显然是不应该发生的。
三、通过super解决初始化问题
class Electrical(object):
def __init__(self, name):
self.name = name
print(Electrical init)
class Phone(Electrical):
def __init__(self, price, *args):
super(Phone, self).__init__(*args)
self.price = price
print(Phone init)
class Computer(Electrical):
def __init__(self, config, *args):
super(Computer, self).__init__(*args)
self.config = config
print(Computer init)
class HuaWei(Phone, Computer):
def __init__(self, name, price, config):
super(HuaWei, self).__init__(name, price, config)
print(HuaWei init)
h = HuaWei(huawei, 100, i7)
运行结果:
Electrical init
Computer init
Phone init
HuaWei init
通过super方法,我们解决了Electrical初始化两次的问题,现在的继承关系就是正常的了。
注意:在Phone类和Computer类中给super()后的init方法传参数时,应使用*args,因为HuaWei有三个参数,但是Phone类和Computer类都只有两个参数,所以参数个数不正确会报错。
四、菱形继承的继承顺序
class Electrical(object):
def chat(self):
print(Chat with friend in electrical!)
def watch_movie(self):
print(Watch movie in electrical!)
def game(self):
print(Play game in electrical!)
class Phone(Electrical):
def game(self):
print(Play game in phone!)
class Computer(Electrical):
def watch_movie(self):
print(Watch movie in computer!)
def game(self):
print(Play game in computer!)
class HuaWei(Phone, Computer):
pass
h = HuaWei()
h.game()
h.watch_movie()
h.chat()
运行结果:
Play game in phone!
Watch movie in computer!
Chat with friend in electrical!
在上面的继承关系中,HuaWei类中一个方法也没有实现,所以类对象调用方法都是要去父类中找。
game()方法在三个类中都实现了,调用了Phone类中的方法,说明最先会去Phone类中查找。
watch_movie()方法在Phone类中也没有实现,调用了Computer类中的方法,说明第二个会去Computer类中查找。
chat()方法在Phone类和Computer类中都没有实现,调用了Electrical类中的方法,说明最后会去Electrical类中查找。
注意:在继承时,如果小括号()中先写Computer再写Phone,则两个类的继承顺序就会调换。
由此,我们可以得出菱形继承的继承顺序了。如下图所示。
五、__mro__方法查看继承顺序
根据上面的案例,我们已经知道了菱形继承中的继承顺序了。
这种继承顺序是遵循广度优先算法的。也就是说,多层多继承时,先在父级中按先后顺序查找,然后在到父级的父级中查找。
这样,继承顺序已经很清晰了,不过,这还需要我们人工来识别继承顺序。如果继承关系非常复杂,像一张网一样,我们再去人工识别继承顺序将会非常困难,并且容易出错。
在Python中,已经定义了一个魔法方法来帮助我们查看类的继承顺序,这个方法就是__mro__方法。
print(HuaWei.__mro__)
运行结果:
(
<class __main__.HuaWei>,
<class __main__.Phone>,
<class __main__.Computer>,
<class __main__.Electrical>,
<class object>
)
mro是 Method Resolution Order (方法解析顺序)的简写,我们可以直接打印类的__mro__方法来获取类的继承顺序。
注意:__mro__只能通过类对象来使用,不能通过实例对象来使用。
以上是关于Python菱形继承的初始化问题和继承顺序的主要内容,如果未能解决你的问题,请参考以下文章