一、继承介绍
1 什么是继承
继承是一种新建类的方式,新建的类称之为子类,被继承的类称之为
父类、基类、超类
python支持多继承
2 为何要继承
子类会遗传父类的属性,所以继承是用来解决类与类之间代码冗余问题
3、如何实现继承
class Parent1: # 定义父类
pass
class Parent2: # 定义父类
pass
class Sub1(Parent1): # 单继承
pass
class Sub2(Parent1, Parent2): # 多继承
pass
通过类的内置属性 base 可以查看类继承的所有父类
print(Sub1.__bases__)
print(Sub2.__bases__)
# 在python2中:
# 经典类:没有显式的继承object的类,以及该类的子类都是经典类
# 新式类:显式的继承object的类以及该类的子类,都是新式类
# 在python3中:统一都是新式类
# Ps:object类提供了一些常用内置方法的实现, 用来打印对象时返回字符串的内置方法_str_
# 要找出类与类hi见的继承关系,需要先抽象,再继承。抽象即总结相似之处,总结对象之间的相似之处得到类,总结类鱼类之间的相似之处就可以得到父类。
# 字类可以继承/遗传父类所有的属性,因而继承可以用来解决类与类之间的代码重用性问题
按照定义Student类的方式再定义一个Teacher类的继承案列:
class OldboyPeople:
school = "oldboy"
class Student(OldboyPeople):
def __init__(self, name, age, gender, stud_id, course):
self.name = name
self.age = age
self.gender = gender
self.stu_id = stud_id
self.course = course
def choose(self):
print('%s 正在选课' % self.name)
class Teacher(OldboyPeople):
def __init__(self, name, age, gender, salary, level):
self.name = name
self.age = age
self.gender = gender
self.salary = salary
self.level = level
def score(self, stu, num):
stu.num = num
stu1 = Student("艾利克斯", 73, 'male', 1001, "python全栈开放")
tea1 = Teacher("egon", 18, 'male', 2000, 10)
print(stu1.school)
二、在子类派生的新方法中重用父类的功能方式一
# 在子类派生的新方法中重用父类的功能
# 方式一:指名道姓地调用某一个类的函数
# 特点:不依赖于继承关系
#
class OldboyPeople:
school = "oldboy"
# 空对象,"艾利克斯",73,'male'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def f1(self):
print('1111111')
class Student(OldboyPeople):
# 空对象,"艾利克斯",73,'male',1001,"python全栈开放"
def __init__(self,name,age,gender,stu_id,course):
OldboyPeople.__init__(self,name,age,gender) # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
self.stu_id = stu_id
self.course = course
def choose(self):
print('%s 正在选课' %self.name)
def f1(self):
OldboyPeople.f1(self)
print("22222")
class Teacher(OldboyPeople):
def score(self,stu,num):
stu.num = num
stu1=Student("艾利克斯",73,'male',1001,"python全栈开放")
tea1=Teacher("egon",18,'male',2000,10)
stu1.f1()
三、属性查找
# 有了继承关系,对象再查找属性是,先从对象自己的_dict_中找,如果没有则取子类中找,然后再去父类中找
# obj.f1()会在父类Foo中找到f1,先打印Foo.f1,然后执行到self.f2(),即obj.f2(),仍会按照:
# 对象本身-》类Bar-》父类Foo的顺序依次找下去,再类Bar中找到f2,因而打印结果位Foo.f2
# 例1:
# class Foo:
# def f2(self):
# print("Foo.f2")
#
# def f1(self):
# print('Foo.f1')
# self.f2() # obj.f2()
#
#
# class Bar(Foo):
# def f2(self):
# print("Bar.f2")
# obj = Bar() # Foo.f1
# obj.f1() # Bar.f2
# 例2:父类如果不想让子类覆盖自己的方法,可以在方法名前加前缀__设置位私有的
class Foo:
def __f2(self): # _Foo__f2
print("Foo.f2")
def f1(self):
print('Foo.f1')
self.__f2() # obj._Foo__f2()
class Bar(Foo):
def __f2(self): # _Bar__f2
print("Bar.f2")
obj = Bar()
obj.f1()
四、继承的实现原理
1)补充知识:
新式类:但凡是继承了object类的子类,以该子类子子孙孙类都称之为新式类
经典类:没有继承了object类的子类,以该子类子子孙孙类都称之为经典类
python3中全都是新式类,python2中才有经典类:
在python3中没有继承任何类的类会默认继承object类
class Foo(object):
pass
print(Foo.__bases__) # (<class 'object'>,)
2)继承的实现原理
2.1 菱形问题:一个子类继承的多条件分支最终汇聚到一个非object类,在菱形继承下
新式类与经典类关于属性查找的方式不同
新式类:广度优先
经典类:深度优先
python都会计算出一个方法解析顺序(MRO)列表,该列表就是一个简单的所有基类的线性顺序列表
python会再MRO列表上从左到右开始查找基类,只导找到第一个匹配这个属性的类为止。而这个MRO列表的构造时通过一个C3线性化算法来实现的,我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循三条准则:
1、子类会先于父类被检查
2、多个父类会根据他们再列表中的顺序被检查
3、如果对下一个类存在两个合法的选择,选择第一个父类
所以obj.test()查找顺序时先从对象obj本身的属性里找方法test,没有找到,则参照属性查找的发起者,所处类D的MRO列表来一次检索,首先在类D中未找到,然后再B中找到方法test
ps:
1、由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去
2、由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去
五、深度和广度优先
如果继承关系位菱形结构,那么经典类和新式类会有不同的MRO,分别对应属性的两种查找方式:深度优先和广度优先
例1:非菱形继承,经典类与新式类的属性查找顺序都一样
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')
class D:
def test(self):
print('from D')
class A(B, C, D):
def test(self):
print('from A')
pass
obj=A()
obj.test()
# 例2:菱形继承
class G(object): # 在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')
pass
class B(E):
def test(self):
print('from B')
pass
class C(F):
def test(self):
print('from C')
pass
class D(G):
def test(self):
print('from D')
pass
class A(B,C,D):
def test(self):
print('from A')
pass
obj=A()
obj.test()