一、继承
1.1、什么是继承
继承是一种创建新类的方式,新建的类可以称为子类或者派生类,父类可以称为基类或者超类,子类会遗传父类
1.2、Python中的继承
python中支持多继承关系,一个子类可以继承一个或者多个父类
class Parent1object): x=1111 class Parent2object): pass class Sub1Parent1): # 单继承 pass class Sub2Parent1,Parent2): # 多继承 pass printSub1.__bases__) printSub2.__bases__) printSub1.x)
1.3、python2以及python3中继承的区别
python2
新类式:继承可了object类的子类
经典式:没有继承object类的子类
python3
python3中只有新类式,没有继承任何类的都会默认继承object类
1.4、python的多继承
优点:
子类可以继承多个父类,最大程度的限制重用代码
缺点:
1、违背人的思维习惯,继承表达的是一种什么是什么的关系
2、代码可读性变差
3、不建议使用多继承,有肯能会引发菱形问题,扩展性变差
注:
如果不可避免的需要使用到多个父类的属性,应该使用mixins
1.5、为什么要使用继承
解决类与类之间的代码冗余问题
1.6、怎么实现继承
当子类需要的代码都在父类中时,可以直接引用
当子类需要的代码只有部分在父类时,编写类,再指名道姓的从父类中引用代码例如:
def __init__self, name, age, sex, salary, level): 类
OldboyPeople.__init__self,name,age, sex)
class OldboyPeople: #通用的父类代码 school = 'OLDBOY' def __init__self, name, age, sex): self.name = name self.age = age self.sex = sex class StudentOldboyPeople): #子类代码和父类代码一致,直接从父类代码中引用 def choose_courseself): print'学生%s 正在选课' % self.name) stu_obj = Student'lili', 18, 'female') stu_obj.choose_course) class TeacherOldboyPeople): #子类代码中只有部分功能在父类中 老师的空对象,'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 scoreself): print'老师 %s 正在给学生打分' % self.name) tea_obj=Teacher'egon',18,'male',3000,10) tea_obj.score)
二、继承属性的查找
2.1、有了继承关系之后,对象在查找属性时,会先从自身__dict__里面找,如果没有回去子类中查找,最后到父类中
例题一:子类中没有找到,在父类中找到,父类的函数下子类和父类中都有,会直接先从子类中读取
class Foo: def f1self): print'Foo.f1') def f2self): print'Foo.f2') self.f1) # obj.f1) class BarFoo): def f1self): print'Bar.f1') obj=Bar) obj.f2) #Foo.f2 Foo.f1
3.2、子类中找不到的情况下,在父类中找到了,接着父类的函数会直接指向子类,如果要强行指向父类中,需要指明道姓的调用父类函数:Foo.f1self)
class Foo: def f1self): print'Foo.f1') def f2self): print'Foo.f2') Foo.f1self) # 调用当前类中的f1 class BarFoo): def f1self): print'Bar.f1') obj=Bar) obj.f2) # Foo.f2 # Foo.f1
3.3、从父类调用时,遇到隐藏属性的类,名字将会变形,但是对外不对内,所以自找到父类中的函数
class Foo: def __f1self): # _Foo__f1 print'Foo.f1') def f2self): print'Foo.f2') self.__f1) # self._Foo__f1,# 调用当前类中的f1 class BarFoo): def __f1self): # _Bar__f1 print'Bar.f1') obj=Bar) obj.f2) # Foo.f2 # Foo.f1
四、多继承关系带来的菱形问题
4.1、菱形问题以及MRO的介绍
菱形问题指的是有多个父类,父类最终又指向同一个父类
MRO:指的是类的对象访问属性的查找顺序是根据MRO的显示
4.2、查找顺序
非菱形:
按照子类的父类从左到右的顺序,一个分支一个分支的找下去,
菱形:
经典型:深度优先,每一个分支找到底,直到最终的父类,第二个分支将不会找最终的父类
新类型:广度优先,最后一个分支才会找到最终的父类,其余的父类都会直接跳过
class G: # 在python2中,未继承object的类及其子类,都是经典类
# def testself):
# print'from G')
pass
class EG):
# def testself):
# print'from E')
pass
class FG):
def testself):
print'from F')
class BE):
# def testself):
# print'from B')
pass
class CF):
def testself):
print'from C')
class DG):
def testself):
print'from D')
class AB,C,D):
# def testself):
# print'from A')
pass
# 新式类
# printA.mro)) # A->B->E->C->F->D->G->object
# 经典类:A->B->E->G->C->F->D
obj = A)
obj.test) #
4.3、总结
多继承要不要用?
要用,但是需要规避几个问题
1.继承结构不要过于复杂
2.推荐使用mixins机制,在多继承的背景下满足什么是什么的关系
5、mixins机制
多继承的正确打开方式:mixins
mixins的核心:在多继承的背景下,尽可能的提升多继承的可读性,也就是让多继承满足人的思维方式===》什么是什么
汽车和飞机都属于交通工具,其中两种飞机有属于能飞的,所以父类的条件是交通工具和能飞,将能飞这个条件提取出来,单独放在左边,因为新类型最后再回找最终的父类。
class Vehicle: pass class FlyableMixin: def flyself): pass class CivilAircraftFlyableMixin,Vehicle): # 民航飞机 pass class HelicopterFlyableMixin,Vehicle): # 直升飞机 pass class CarVehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了 pass import socketserver # 补充:通常Mixin结果的类放在左边
六、子类中如何应用父类的功能
使用super()调用父类提供给自己的方法====》严格依赖继承关系
调用super()会得到一个特殊的对象,该对象会参考发起属性查找那个类MRO,去当前父类中查找属性(mro中的属性)
class OldboyPeople: def __init__self,name,age,sex): self.name=name self.age=age self.sex=sex def f1self): print'%s say hello' %self.name) class TeacherOldboyPeople): def __init__self,name,age,sex,level,salary): # superTeacher,self).__init__name,age,sex) super).__init__name,age,sex) # 调用的是方法,自动传入对象 self.level = level self.salary=salary # printTeacher.mro)) tea_obj=Teacher'egon',18,'male',10,3000) printtea_obj.__dict__)