继承
(父类派生子类,子类继承父类)
通过继承,可以让子类去拥有父类中的属性和方法,而不必重新编写相同的代码,并且可以在父类的基础上添加新的属性和功能。
在继承的同时,子类还可以重写父类中的方法,从而获取与父类不同的功能,实现多态。
在 Python 中 所有的类都是存在继承关系的,没有显示继承的,都是默认继承 object 类
提高开发效率,避免代码冗余
#多重单继承初始化问题
class Person(object):
def __init__(self, name): # <__main__.Son object at 0x7f95c505d630>
self.__name = name
print("Person init")
def get_name(self):
print(self.__name)
class Parent(Person):
def __init__(self, name, age): # <__main__.Son object at 0x7f95c505d630>
Person.__init__(self, name)
self.__age = age
print("Parent init")
def get_age(self):
print(self.__age)
class Son(Parent):
def __init__(self, name, age, gender):
Parent.__init__(self, name, age)
self.__gender = gender
print("Son init")
def get_gender(self):
print(self.__gender)
wo = Son('tom', 22, 'male')
wo.get_name()
wo.get_age()
wo.get_gender()
>>>Person init
Parent init
Son init
tom
22
male
当在初始化时,子类只需要初始化自己扩展的属性即可,父类中的属性交给父类去初始化。
多重多继承的初始化问题
class Person(object):
def __init__(self, name):
self.__name = name
print("Person init")
def get_name(self):
return self.__name
class Monther(Person):
def __init__(self, name, job):
Person.__init__(self, name)
self.__job = job
print("Monther init")
def get_job(self):
return self.__job
class Parent(Person):
def __init__(self, name, age):
Person.__init__(self, name)
self.__age = age
print("Parent init")
def get_age(self):
return self.__age
class Son(Parent, Monther):
def __init__(self, name, age, job, gender):
Parent.__init__(self, name, age)
Monther.__init__(self, name, job)
self.__gender = gender
print("Son init")
def get_gender(self):
return self.__gender
wo = Son('tom', 22, 'teacher', 'male')
print(wo.get_name(), wo.get_age(), wo.get_job(), wo.get_gender())
>>>Person init
Parent init
Person init
Monther init
Son init
tom 22 teacher male
很明显这是不对的,因为 Father 类和 Mother 类都是继承于 Person 类的,在自己的初始化方法中,执行了父类的初始化方法,所以执行了两次,造成了代码冗余
多重多继承 =》 person被调用多次 ==> object更多次
super 函数
super函数解决继承中父类被重复初始化问题
super函数的格式
super(CurrentClassName, self).init(*args, **kwargs)
class Person(object):
def __init__(self, name):
self.__name = name
print("Person init")
def get_name(self):
return self.__name
class Mother(Person):
def __init__(self, job, *args):
super(Mother, self).__init__(*args)
self.__job = job
print("Mother init")
def get_job(self):
return self.__job
class Father(Person):
def __init__(self, age, *args):
super(Father, self).__init__(*args)
self.__age = age
print("Father init")
def get_age(self):
return self.__age
class Son(Father, Mother):
def __init__(self, name, age, job, gender):
super(Son, self).__init__(name, age, job)
self.__gender = gender
print("Son init")
def get_gender(self):
return self.__gender
wo = Son('tom', 22, 'teacher', 'male')
print(wo.get_name(), wo.get_age(), wo.get_job(), wo.get_gender())
>>>Person init
Mother init
Father init
Son init
teacher tom 22 male
通过执行结果来看,使用 super 改进后的代码只初始化了一次 Person 的初始化方法。
###钻石继承
##mro
mro Method Resolution Order 方法解析顺序
在类出现继承时,每个类中都会保存一个当前类的继承关系的表。
super 函数在执行时,会在自己保存的这个继承关系中去查找第一个参数,也就是当前的类名的下一个类是谁。然后去调用下个类的初始化方法。
Python 中使用广度优先算法来决定继承关系的排序
Mro顺序
print(Son.__mro__)
>>>(<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class '__main__.Person'>, <class 'object'>)
在初始化父类时,也可以使用 super().init() 函数来调用,简化super函数的写法。
这时,super函数中没有参数,还是能正确执行,就是依照 mro 中的顺序来执行的。
super().__init__(*args)
对象在调用方法时,也会依照这个顺序来查找方法。
类在继承时,继承关系的书写顺序会影响 mro 中的顺序。