继承与派生
一:认识继承
什么是继承?
继承是一种创建新类的方式,创建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生或子类
子类会遗传父类的属性,从而解决代码重用性的问题
python中的继承分为单继承和多继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
新式类和经典类
在python3中所有的类都是新式类
在Python2中所有的没有显示的继承object的类及其子类都是经典类
在Python2中所有的显示的继承object的类及其子类都是新式类
注意:如果没有指定基类,在python3中会默认继承object类,object类是所有python类的基类
二:继承与抽象
继承描述的是子类与父类之间的关系,具体一种什么样的关系,需要先抽象,找出关系,才能来继承
抽象:即把对象相似的特征抽取出来
定义两个类,学生类和老师类,其共同点在于他们都有名字和年龄、性别,把这一部分抽取出来,组成一个类:人类,
人类和学生类、老师类的关系可以很清楚的看到:学生类和老师类继承人类
于是:继承就是基于抽象的结果,通过编程语言去实现它
三:继承与重用
在子类派生出的新方法中重用父类的功能
方式一:指名道姓的调用,该方法与继承实际没有关系
class OldboyPeople: school = "oldboy" def __init__(self,name,age,sex): self.name = name self.age = age self.sex =sex class Student(OldboyPeople): def choose(self): print("stu %s choose course..."%self.name) class Teacher(OldboyPeople): def __init__(self,name,age,sex,salary,level): OldboyPeople.__init__(Teacher,name,age,sex) self.salary =salary self.level =level def change_score(self): print("tec %s change score..."%self.name) t2 = Teacher("alex",38,"male",3.1,9) t3 = Teacher("egon",18,"male",33,10) print(t2.school,t2.name,t2.level,t2.salary,t2.age) print(t3.school,t3.name,t3.level,t3.salary,t3.age)
方式二:super()调用,严格依赖于继承,super()的返回值是一个特殊的对象,该对象专门用来调用父类当中的属性
class OldboyPeople: school = "oldboy" def __init__(self,name,age,sex): self.name = name self.age = age self.sex =sex class Student(OldboyPeople): def choose(self): print("stu %s choose course..."%self.name) class Teacher(OldboyPeople): def __init__(self,name,age,sex,salary,level): super().__init__(name,age,sex) self.salary =salary self.level =level def change_score(self): print("tec %s change score..."%self.name) t2 = Teacher("alex",38,"male",3.1,9) t3 = Teacher("egon",18,"male",33,10) print(t2.school,t2.name,t2.level,t2.salary,t2.age) print(t3.school,t3.name,t3.level,t3.salary,t3.age)
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.
四:派生
子类同样也可以添加自己的新属性或者重新定义这些属性(这样做不会对父类产生影响),需要注意的是:如果子类定义的属性名和父类同名,那么在调用新增的属性时,以自己的为准
class Foo: def __int__(self): pass def f1(self): self.f1() print("from foo") class Bar(Foo): def __int__(self): pass def f1(self): print("from bar") b1 = Bar() b1.f1()
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
class Foo: def __int__(self): pass def f1(self): print("from foo") class Bar(Foo): def __int__(self): pass def f1(self): Foo.f1(Bar) super().f1() print("from bar") b1 = Bar() b1.f1() # from foo # from foo # from bar
五:继承顺序
1、新式类
继承object的类以及他的子类都是新式类
没有继承object的类以及他的子类都是经典类
非菱形背景下属性查找:
不区分新式类还是经典类,从左至右一个个查找到底
菱形背景下属性查找
经典类:深度优先
新式类:广度优先
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'>]
A没有继承B,但是A内super会基于C.mro()继续往后找