继承与派生
Posted 蜗牛也是妞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了继承与派生相关的知识,希望对你有一定的参考价值。
1 什么是继承
是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余在python中,子类(派生类)可以继承一个或者多个父类(基类,超类)
class Parent1: #定义父类 pass class Parent2(object): #定义父类 pass class Sub1(Parent1): #单继承,基类是ParentClass1,派生类是SubClass pass class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类 pass print(Sub1.__bases__)#__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 print(Sub2.__bases__) print(Parent1.__bases__) print(Parent2.__bases__)
2 经典类与新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
4.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
3 属性查找
先从自己类中查找,再然后再去父类中找...直到最顶级的父类。
#属性查找 class Foo: def f1(self): print(\'Foo.f1\') def f2(self): #self=obj print(\'Foo.f2\') self.f1() #obj.f1() class Bar(Foo): def f1(self): print(\'Bar.f1\') obj=Bar() print(obj.__dict__) obj.f2() \'\'\'{} Foo.f2 Bar.f1 \'\'\'
4 子类重用父类的方法
#方法一(不建议用) class OldboyPeople: school = \'Oldboy\' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(\'<名字:%s 年龄:%s 性别:%s>\' %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,course,stu_id): OldboyPeople.__init__(self,name,age,sex)#调用父类的方法 self.course=course self.stu_id=stu_id def learn(self): print(\'%s is learning\' %self.name) def tell_info(self): print(\'我是学生:\',end=\'\') # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) #调用父类的方法 stu1=OldboyStudent(\'牛榴弹\',18,\'male\',\'Python\',1) stu1.tell_info()
#方法二:使用super关键字 class OldboyPeople: school = \'Oldboy\' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(\'<名字:%s 年龄:%s 性别:%s>\' %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,course): # OldboyPeople.__init__(self,name,age,sex) super(OldboyStudent,self).__init__(name,age,sex)#使用super关键字 self.course=course def tell_info(self): print(\'我是学生: \',end=\'\') # OldboyPeople.tell_info(self) super(OldboyStudent,self).tell_info() #使用super关键字 stu1=OldboyStudent(\'egon\',18,\'male\',\'python\') # print(stu1.name,stu1.age,stu1.sex,stu1.course) stu1.tell_info()
5 继承的实现原理
1、继承顺序
class A(object): def test(self): print(\'from A\') class B(A): def test(self): print(\'from B\') class C(A): def test(self): print(\'from C\') class D(B): def test(self): print(\'from D\') class E(C): def test(self): print(\'from E\') class F(D,E): # def test(self): # print(\'from F\') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A(广度优先) #经典类继承顺序:F->D->B->A->E->C(深度优先) #python3中统一都是新式类 #pyhon2中才分新式类与经典类
2、继承原理
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
>>> F.mro() #等同于F.__mro__ [<class \'__main__.F\'>, <class \'__main__.D\'>, <class \'__main__.B\'>, <class \'__main__.E\'>, <class \'__main__.C\'>, <class \'__main__.A\'>, <class \'object\'>
]
6 子类中调用父类的方法
#方法一:指名道姓,即父类名.父类方法() #_*_coding:utf-8_*_ class Vehicle: #定义交通工具类 Country=\'China\' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(\'开动啦...\') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) self.line=line def run(self): print(\'地铁%s号线欢迎您\' %self.line) Vehicle.run(self) line13=Subway(\'中国地铁\',\'180m/s\',\'1000人/箱\',\'电\',13) line13.run()
#方法二:super() class Vehicle: #定义交通工具类 Country=\'China\' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(\'开动啦...\') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self) super().__init__(name,speed,load,power) self.line=line def run(self): print(\'地铁%s号线欢迎您\' %self.line) super(Subway,self).run() class Mobike(Vehicle):#摩拜单车 pass line13=Subway(\'中国地铁\',\'180m/s\',\'1000人/箱\',\'电\',13) line13.run()
即使没有直接继承关系,super仍然会按照mro继续往后查找
#A没有继承B,但是A内super会基于C.mro()继续往后找 class A: def test(self): super().test() class B: def test(self): print(\'from B\') class C(A,B): pass c=C() c.test() #打印结果:from B print(C.mro()) #[<class \'__main__.C\'>, <class \'__main__.A\'>, <class \'__main__.B\'>, <class \'object\'>]
#指名道姓 class A: def __init__(self): print(\'A的构造方法\') class B(A): def __init__(self): print(\'B的构造方法\') A.__init__(self) class C(A): def __init__(self): print(\'C的构造方法\') A.__init__(self) class D(B,C): def __init__(self): print(\'D的构造方法\') B.__init__(self) C.__init__(self) f1=D() #A.__init__被重复调用 \'\'\' D的构造方法 B的构造方法 A的构造方法 C的构造方法 A的构造方法 \'\'\' #使用super() class A: def __init__(self): print(\'A的构造方法\') class B(A): def __init__(self): print(\'B的构造方法\') super(B,self).__init__() class C(A): def __init__(self): print(\'C的构造方法\') super(C,self).__init__() class D(B,C): def __init__(self): print(\'D的构造方法\') super(D,self).__init__() f1=D() #super()会基于mro列表,往后找 \'\'\' D的构造方法 B的构造方法 C的构造方法 A的构造方法 \'\'\'
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
以上是关于继承与派生的主要内容,如果未能解决你的问题,请参考以下文章