【目录】
一、继承介绍
二、继承与抽象
三、属性查找
四、继承的实现原理
1、菱形问题
2、继承原理
3、深度优先和广度优先
4、python Mixins机制
五、派生与方法重用
六、组合
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承 pass class SubClass2(ParentClass1,ParentClass2): #多继承 pass
>>> SubClass2.__bases__ (<class ‘__main__.ParentClass1‘>, <class ‘__main__.ParentClass2‘>)
>>> ParentClass1.__bases__ (<class ‘object‘>,) >>> ParentClass2.__bases__ (<class ‘object‘>,)
提示:object类提供了一些常用内置方法的实现,如用来在打印对象时返回字符串的内置方法__str__
为了解决类与类之间,代码冗余的问题
# 优点:
子类可以同时遗传多个父类的属性,最大限度地重用代码
# 缺点:
# 1、违背人的思维习惯:继承表达的是一种什么"是"什么的关系
# 2、代码可读性会变差
# 3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,
# 如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins机制
要找出类与类之间的继承关系,需要先抽象,再继承。
抽象即总结相似之处,总结对象之间的相似之处得到类(子类),
总结类与类之间的相似之处就可以得到父类。
# 示范1:类与类之间存在冗余问题 class Student: school=‘OLDBOY‘ def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def choose_course(self): print(‘学生%s 正在选课‘ %self.name) class Teacher: school=‘OLDBOY‘ def __init__(self,name,age,sex,salary,level): self.name=name self.age=age self.sex=sex self.salary=salary self.level=level def score(self): print(‘老师 %s 正在给学生打分‘ %self.name)
# 示范2:基于继承解决类与类之间的冗余问题 class OldboyPeople: school = ‘OLDBOY‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class Student(OldboyPeople): def choose_course(self): print(‘学生%s 正在选课‘ % self.name) stu_obj = Student(‘lili‘, 18, ‘female‘) print(stu_obj.__dict__) print(stu_obj.school) stu_obj.choose_course() class Teacher(OldboyPeople): # 老师的空对象,‘egon‘,18,‘male‘,3000,10 def __init__(self, name, age, sex, salary, level): # 指名道姓地跟父类OldboyPeople去要__init__ OldboyPeople.__init__(self,name,age, sex) self.salary = salary self.level = level def score(self): print(‘老师 %s 正在给学生打分‘ % self.name) tea_obj=Teacher(‘egon‘,18,‘male‘,3000,10) print(tea_obj.__dict__) print(tea_obj.school) tea_obj.score() # 输出结果: {‘name‘: ‘lili‘, ‘age‘: 18, ‘sex‘: ‘female‘} OLDBOY 学生lili 正在选课 {‘name‘: ‘egon‘, ‘age‘: 18, ‘sex‘: ‘male‘, ‘salary‘: 3000, ‘level‘: 10} OLDBOY 老师 egon 正在给学生打分
有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找……
# 示范一: class Foo: def f1(self): print(‘Foo.f1‘) def f2(self): print(‘Foo.f2‘) self.f1() # obj.f1() # 调用类Bar中的f1—— 先从自身对象找,没有再去自己的类Bar中有没有f1,没有再去继承的类Foo中找
class Bar(Foo): def f1(self): print(‘Bar.f1‘) obj=Bar() obj.f2() # 输出结果: # Foo.f2 # Bar.f1
# # 示范二: class Foo: def f1(self): print(‘Foo.f1‘) def f2(self): print(‘Foo.f2‘) Foo.f1(self) # 调用当前类Foo中的f1 class Bar(Foo): def f1(self): print(‘Bar.f1‘) obj=Bar() obj.f2() #输出结果: # Foo.f2 # Foo.f1
# 示范三: class Foo: def __f1(self): # _Foo__f1 print(‘Foo.f1‘) def f2(self): print(‘Foo.f2‘) self.__f1() # self._Foo__f1,# 调用当前类中的f1 class Bar(Foo): def __f1(self): # _Bar__f1 print(‘Bar.f1‘) obj=Bar() obj.f2() # 输出结果: # Foo.f2 # Foo.f1
a类在顶部,b类和c类分别位于其下方,d类在底部将两者连接在一起形成菱形
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,C): pass obj = D() obj.test() # 结果为:from B
>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法 [<class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>]
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去
#【test1】 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(C,B): def test(self): print(‘from D‘) print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表 # 输出结果: # [<class ‘__main__.D‘>, <class ‘__main__.C‘>, <class ‘__main__.B‘>, <class ‘__main__.A‘>, <class ‘object‘>] obj1 = D() obj1.test() # 输出结果:from D print(D.test) # 输出结果:<function D.test at 0x0000012EA27FA4C0> print(C.mro()) # 类C以及类C的对象访问属性都是参照该类的mro列表 # 输出结果:[<class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>] obj2 = C() obj2.test() # 输出结果:from C print(C.test) # 输出结果: <function C.test at 0x0000022FA7D0A3A0> # 【test2】 class A(object): # def test(self): # print(‘from A‘) pass class B(A): def test(self): print(‘from B‘) class C(A): # def test(self): # print(‘from C‘) pass class D(C,B): # def test(self): # print(‘from D‘) pass print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表 # 输出结果: # [<class ‘__main__.D‘>, <class ‘__main__.C‘>, <class ‘__main__.B‘>, <class ‘__main__.A‘>, <class ‘object‘>] obj1 = D() obj1.test() # 输出结果:from B print(D.test) # 输出结果:<function B.test at 0x00000246D6F3A310> # 总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro
class E: # def test(self): # print(‘from E‘) pass class F: def test(self): print(‘from F‘) class B(E): # def test(self): # print(‘from B‘) pass class C(F): # def test(self): # print(‘from C‘) pass class D: def test(self): print(‘from D‘) class A(B, C, D): # def test(self): # print(‘from A‘) pass # 新式类 print(A.mro()) # A->B->E->C->F->D->object # [<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, # <class ‘__main__.C‘>, <class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘object‘>] obj = A() obj.test() # 结果为:from F
class G: # 在python2中,未继承object的类及其子类,都是经典类 # def test(self): # print(‘from G‘) pass class E(G): # def test(self): # print(‘from E‘) pass class F(G): def test(self): print(‘from F‘) class B(E): # def test(self): # print(‘from B‘) pass class C(F): def test(self): print(‘from C‘) class D(G): def test(self): print(‘from D‘) class A(B,C,D): # def test(self): # print(‘from A‘) pass # # 新式类 print(A.mro()) # # A->B->E->C->F->D->G->object # # [<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.F‘>, # # <class ‘__main__.D‘>, <class ‘__main__.G‘>, <class ‘object‘>] obj = A() obj.test() # 输出结果:from C # 经典类:A->B->E->G->C->F->D print(A.mro()) obj = A() obj.test() # 输出结果:from C
# 多继承到底要不用?
要用,但是规避几点问题——
# 1、继承结构尽量不要过于复杂
# 2、推荐使用mixins机制:在多继承的背景下满足继承的什么"是"什么的关系
参考:
原文:https://www.cnblogs.com/bigorangecc/p/12665092.html