Python进阶之继承
【一】什么是继承
-
继承是一种创建新类的方式,新建的类可以继承一个或多个父类
-
父类又可称为基类或超类,新建的类称为派生类或子类
-
子类通过继承父类,减少了重复代码的使用
【二】继承的分类
【1】单继承
- 单继承就是只继承一个父类的子类
# 父类
class School(object):
school = "北京大学"
# 子类:继承了父类School
class Student(School):
def __init__(self, name):
self.__name = name
def __read(self):
print(f"学生{self.__name}的学校是{self.school}")
def read(self):
self.__read()
student = Student('ligo')
student.read()
# 学生ligo的学校是北京大学
【2】多继承
- 多继承就是继承多个父类的子类
# 父类1
class Person(object):
age = 18
# 父类2
class School(object):
school = "北京大学"
# 子类:继承了父类School和Person
class Student(School,Person):
def __init__(self, name):
self.__name = name
def __read(self):
print(f"{self.age}岁的学生{self.__name}的学校是{self.school}")
def read(self):
self.__read()
student = Student('ligo')
student.read()
# 18岁的学生ligo的学校是北京大学
【三】查看继承父类的方式
# 父类1
class Person(object):
age = 18
# 父类2
class School(object):
school = "北京大学"
# 子类1:继承了父类School
class Student1(School):
def __init__(self, name):
self.__name = name
def __read(self):
print(f"学生{self.__name}的学校是{self.school}")
def read(self):
self.__read()
# 子类2:继承了父类School和Person
class Student2(School, Person):
def __init__(self, name):
self.__name = name
def __read(self):
print(f"{self.age}岁的学生{self.__name}的学校是{self.school}")
def read(self):
self.__read()
# __base__只查看从左到右继承的第一个子类,如果继承多个父类,默认只打印第一个继承的父类
print(Student1.__base__) # <class '__main__.School'>
print(Student2.__base__) # <class '__main__.School'>
# __bases__查看当前所有继承的父类,打印成一个元祖输出
print(Student1.__bases__) # (<class '__main__.School'>,)
print(Student2.__bases__) # (<class '__main__.School'>, <class '__main__.Person'>)
【四】经典类与新式类
- 经典类和新式类的区别在于Python版本的不同
- 经典类:在python2中,没有显示继承object的类,以及该类的子类,都是经典类
- 新式类:在python2中,显示继承object的类,以及该类的子类,都是新式类
- 在python3中,无论是否继承object,都默认继承object,即python3中所有类都默认为新式类
【五】继承和抽象
- 继承描述的是子类与父类之间的关系,是一种什么是什么的关系
- 要找出这种关系,必须先抽象再继承
- 抽象即抽取类似或者说比较像的部分
【1】什么是继承和抽象
(1)抽象
- 抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
- C罗,杜兰特这类对象属于人,小猪佩奇,猪猪侠这类对象属于猪,黑猫警长,波比这类对象属于猫
- 人、猪、猫可以归类成动物
(2)继承
- 继承:是基于抽象的结果,一定是先抽象再继承
- 继承是由少变多,抽象是由多变少
【2】继承的实现
(1)没有继承和抽象,单独成类
- 猫和狗各自有一个单独的类
class Dog(object):
def run(self):
print("狗可以到处跑!")
def eat(self):
print("狗可以吃饭!")
def drink(self):
print("狗可以喝水!")
class Cat(object):
def run(self):
print("猫可以到处跑!")
def eat(self):
print("猫可以吃饭!")
def drink(self):
print("猫可以喝水!")
(2)抽象成类
- 将猫和狗总结成一个类,可以跑,可以吃饭,可以喝水
class Animal(object):
def run(self):
print(f"{self.name}可以到处跑!")
def eat(self):
print(f"{self.name}可以吃饭!")
def drink(self):
print(f"{self.name}可以喝水!")
(3)继承总类
class Animal(object):
def run(self):
print(f"{self.name}可以到处跑!")
def eat(self):
print(f"{self.name}可以吃饭!")
def drink(self):
print(f"{self.name}可以喝水!")
class Dog(Animal):
def __init__(self, name):
self.name = "小狗" + name
class Cat(Animal):
def __init__(self, name):
self.name = "小猫" + name
dog = Dog("小七")
dog.run() # 小狗小七可以到处跑!
cat = Cat('波比')
cat.eat() # 小猫波比可以吃饭
【六】属性查找顺序
【1】不隐藏属性的查找顺序
- 有了继承关系,查找属性时先从对象自己的
__dict__
中找,如果没有则去子类中找,然后再去父类中找
class Foo:
def f1(self):
print('Foo.f1')
# 【3】在父类Foo中找到f2
def f2(self):
# 【4】先打印 Foo.f2
print('Foo.f2')
# 【5】
# 但是这里犯了难,这个 self 到底是 Foo 还是 Bar ?
# 我们要时刻记得,源头是谁,这个self就是谁
# 我们是从 对象 b 来的,而对象 b 又是 Bar 的对象
# 我们从 Bar 找到了 Foo 类里面,所以我们的源头就是 Bar
# 那这个 self 就是 Bar , 而 Bar 类里面有 f1 方法
# 所以我们就会回到 Bar 类里面
self.f1()
class Bar(Foo):
# 【2】在Bar中找f2,找不到f2,去Foo找
# 【6】返回到bar中的f1
def f1(self):
# 【7】打印Bar.f1
print('Bar.f1')
# 实例化类得到对象
b = Bar()
# 【1】对象调用方法
b.f2()
# 所以打印的顺序是Foo中的f2,Bar中的f1
# Foo.f2
# Bar.f1
【2】隐藏属性的查找顺序
class Foo:
# 变形为_Foo__fa
def __f1(self):
print('Foo.f1')
# 在父类Foo中找到f2
def f2(self):
# 打印 Foo.f2
print('Foo.f2')
# 调用__f1,又输出Foo.f1
self.__f1()
class Bar(Foo):
# 变形为_Bar__f1,找不到f2,去Foo找
def __f1(self):
print('Bar.f1')
b = Bar()
b.f2()
# Foo.f2
# Foo.f1
【3】总结
- 如果属性不封装的情况下,谁实例化得到的self 就去谁里面找
- 如果属性封装的情况下 , 谁实例化得到的self无效,只能在当前所在的类的民称空间里面找
【七】继承实现的原理
【1】非菱形结构继承顺序
- 在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)
- 如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
【2】菱形结构继承顺序
- 继承关系为菱形结构时属性的查找方式为:深度优先和广度优先
(1)深度优先
- 当类是经典类时,多继承情况下,在查找属性不存在时,会按照深度优先的方式查找下去
(2)广度优先
- 当类是新式类时,多继承情况下,在查找属性不存在时,会按照广度优先的方式查找下去
(3)继承原理
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__)
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
# 新式类继承顺序:F->D->B->E->C->A
# 经典类继承顺序:F->D->B->A->E->C