1、什么是继承?

继承指的是类与类之间的关系是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类

父类又可以称为基类或超类

新建的类称为派生类或子类

2、python中类的继承分为:单继承和多继承

  1. class ParentClass1: #定义父类
  2. pass
  3.  
  4. class ParentClass2: #定义父类
  5. pass
  6.  
  7. class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
  8. pass
  9.  
  10. class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
  11. pass
  1. print(SubClass1.__bases__)
    print(SubClass2.__bases__)
    结果:

(<class '__main__.ParentClass1'>,)
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

_bases_查看继承的父类,输出用元组表示

3、继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

4、继承与重用性

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

  1. 盖伦和瑞文都继承同一个父类(Hero)的属性
    class Hero:
  2. def __init__(self,nickname,aggressivity,life_value):
  3. self.nickname = nickname
  4. self.aggressivity = aggressivity
  5. self.life_value = life_value
  6. def move_forward(self):
  7. print(f"move_forward{self.nickname}")
  8. def move_backward(self):
  9. print(f"move_backward{self.nickname}")
  10. def move_left(self):
  11. print(f"move_left{self.nickname}")
  12. def move_right(self):
  13. print(f"move_right{self.nickname}")
  14. def ack(self,enemy):
  15. enemy.life_value -= self.aggressivity
  16. class Garen(Hero):
  17. pass
  18. class Riven(Hero):
  19. pass
  20. hero = Garen('dema',30,200)
  21. hero2 = Riven('HAHA',50,150)
  22. print(hero2.life_value)
  23. hero.ack(hero2)
  24. print(hero2.life_value)

5、属性查找顺序,先从对象中查找,再到对象类中(实例属性中查找_init_,再到类属性查找),然后从父类中查找

提示:像上个例题中 hero.life_value之类的属性引用,会先从实例中找life_value然后去类中找

然后再去父类中找...直到最顶级的父类。那么如何解释下面的打印结果呢?

  1. class Foo:
  2. def f1(self):
  3. print('Foo.f1')
  4.  
  5. def f2(self):
  6. print('Foo.f2')
  7. self.f1()
  8.  
  9. class Bar(Foo): # 对象的类
  10. def f1(self):
  11. print('Bar.f1')
  12. b=Bar()# 定义对象
  13. b.f2() # 实例化对象
    结果:

Foo.f2
Bar.f1

  1.  

6、派生

子类派生出自己新的属性(相对于继承的父类而言)

当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

  1. class Riven(Hero):
  2. camp='Noxus'
  3. def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类
  4. print('from riven')
  5. def fly(self): #在自己这里定义新的
  6. print('%s is flying' %self.nickname)

7、继承的实现原理(多继承查找)C3算法

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

  1. >>> F.mro() #等同于F.__mro__
  2. [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
  3. <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。

我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  1. 子类会先于父类被检查
  2. 多个父类会根据它们在列表中的顺序被检查
  3. 如果对下一个类存在两个合法的选择,选择第一个父类

在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,

如果继承了多个父类,那么属性的查找方式有两种,分别是:深度优先和广度优先

7.1、python2中经典类,没有继承object的类,以及他的子类都称之为经典类

  1. class Foo:
  2. pass
  3. class Bar(Foo):
  4. pass

7.2、python2中新式类,继承object的类,以及他的子类都称之为新式类

  1. class Foo(object):
  2. pass
  3. class Bar(Foo):
  4. pass

7.3、python3,无论是否继承object,都默认继承object,均为新式类

  1. class Foo:# 一个类没有继承object,默认继承object
  2. pass
  3. print(Foo.__bases__)
  4.  
  5. 结果:(<class 'object'>,)

7.4、多继承下属性查找,经典类(深度优先),新式类(广度优先)

经典类:采取 深度优先 的方式查找,先一条道路走到底

新式类 广度优先 查找

  1. # 多继承属性的查找,经典类(深度优先),新式类(广度优先)
  2. class A(object):
  3. def test(self):
  4. print('from A')
  5. class B(A):
  6. def test(self):
  7. print('from B')
  8. class C(A):
  9. def test(self):
  10. print('from C')
  11. class D(B):
  12. def test(self):
  13. print('from D')
  14. class E(C):
  15. def test(self):
  16. print('from E')
  17. class F(D,E):
  18. pass
  19. f1 = F()
  20. f1.test()
  21. print(F.__mro__) # 只有新式类才有这个属性可以查看线性列表,经典类没有这个属性解析方法调用的顺序。
  1. 结果: from D (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
  2.  
  3. <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

若只保留A中的def test(self):查找到的结果如下:

  1. class A(object):
  2. def test(self):
  3. print('from A')
  4. class B(A):
  5. # def test(self):
  6. # print('from B')
  7. pass
  8. class C(A):
  9. # def test(self):
  10. # print('from C')
  11. pass
  12. class D(B):
  13. # def test(self):
  14. # print('from D')
  15. pass
  16. class E(C):
  17. # def test(self):
  18. # print('from E')
  19. pass
  20. class F(D,E):
  21. # def test(self):
  22. # print('from F')
  23. pass
  24.  
  25. f1 = F()
  26. f1.test()
  27. print(F.__mro__)
  28.  
  29. from A
  30. (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
  31.  
  32. <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

8、在子类中调用父类的方法或属性(1、父类名.父类方法() ; 2、super())

在子类派生出的新方法中,往往需要重用父类的方法,我们有两种方式实现

方式一:指名道姓,即父类名.父类方法()

  1. class Vehicle: #定义交通工具类
  2. Country='China'
  3. def __init__(self,name,speed,load,power):
  4. self.name=name
  5. self.speed=speed
  6. self.load=load
  7. self.power=power
  8.  
  9. def run(self):
  10. print('开动啦...')
  11.  
  12. class Subway(Vehicle): #地铁
  13. def __init__(self,name,speed,load,power,line):
  14. Vehicle.__init__(self,name,speed,load,power)#调用父类的函数属性
  15. self.line=line
  16.  
  17. def run(self):
  18. print('地铁%s号线欢迎您' %self.line)
  19. Vehicle.run(self) # 指名道姓的方式,不依赖继承
  20.  
  21. line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
  22. line13.run()
  23.  
  24. 结果:

地铁13号线欢迎您
开动啦...

  1.  

方法二:super()

  1. Vehicle.run(self)
  1. 方式二:super()
  2.  
  3. class Vehicle: #定义交通工具类
  4. Country='China'
  5. def __init__(self,name,speed,load,power):
  6. self.name=name
  7. self.speed=speed
  8. self.load=load
  9. self.power=power
  10.  
  11. def run(self):
  12. print('开动啦...')
  13.  
  14. class Subway(Vehicle): #地铁
  15. def __init__(self,name,speed,load,power,line):
  16. #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
  17. super().__init__(name,speed,load,power)#父类的函数属性
  18. self.line=line
  19.  
  20. def run(self):
  21. print('地铁%s号线欢迎您' %self.line)
  22. super(Subway,self).run() # 等效于Vehicle.run(self)
  1. class Mobike(Vehicle):#摩拜单车
      pass
    line13=Subway('中国地铁','180m/s','1000人/箱','电',13) line13.run()

这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,

并且即使没有直接继承关系,super仍然会按照mro继续往后查找

  1. #A没有继承B,但是A内super会基于C.mro()继续往后找
  2.  
  1. class A:
  2. def test(self):
  3. super().test()
  4. class B:
  5. def test(self):
  6. print('from B')
  7. class C(A,B):
  8. pass
  9.  
  10. c=C()
  11. c.test() #打印结果:from B
  12.  
  13. print(C.mro())#__mro__给出了,即解析方法调用的顺序。
    结果:
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

6 python 继承与派生的更多相关文章

  1. Python 继承、派生、组合、接口、抽象类

    继承是一种是的关系,和组合对比,组合是一种有的关系,这两者都是解决代用重用问题的 继承 注意:继承不是遗传,在显示角度中,是通过对象抽象成类,再把这些类抽象成一个,就是父类.是自下而上的过程,在程序中 ...

  2. python基础——继承与派生、组合

    python基础--继承与派生 1 什么是继承: 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类成为基类或超累,新建的类成为派生类或子类 1.1 继承分为:单 ...

  3. python 全栈开发,Day20(object类,继承与派生,super方法,钻石继承)

    先来讲一个例子 老师有生日,怎么组合呢? class Birthday: # 生日 def __init__(self,year,month,day): self.year = year self.m ...

  4. python的类继承与派生

    一.继承和派生简介: 其实是一个一个事物站在不同角度去看,说白了就是基于一个或几个类定义一个新的类.比如定义了动物类接着派生出了人类,你也可以说人类继承了动物类.一个意思.此外python类似于C和C ...

  5. python基础之类与对象,继承与派生

    类与对象 对象的本质也就是一个名称空间而已,用于存放自己独有的属性,而类中存放的是对象共有的属性. __init__会在调用类时自动触发 调用类时发生两件事: 1.创建一个空对象stu1 2.自动触发 ...

  6. Python(面向对象编程——2 继承、派生、组合、抽象类)

    继承与派生 ''' 继承:属于 组合:包含 一. 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称 ...

  7. Python基础(16)_面向对象程序设计(类、继承、派生、组合、接口)

    一.面向过程程序设计与面向对象程序设计 面向过程的程序设计:核心是过程,过程就解决问题的步骤,基于该思想设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题的简单化,流程化 缺点: ...

  8. Python之面向对象继承和派生

    Python之面向对象继承和派生 什么是继承: 继承是一种创建新的类的方法.在Python中,新建的类可以继承自一个或多个父类.原始类称为基类或超类. 新建的类称为派生类或子类. Python中类的继 ...

  9. Python面向对象编程——继承与派生

    Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...

随机推荐

  1. 几本不错的graphql 电子书

    当前专门讲graphql 的数据不是很多,但是越来越多的graphql 项目的出现以及graphql 自身的 便捷,老外已经有人去写graphql 的设计以及基本使用了. ebooks 地址 http ...

  2. ORTP库移植

    转载,侵删 1.ORTP的引入 为什么要使用RTP:http://blog.51cto.com/ticktick/462746RTP协议分析:http://www.xuebuyuan.com/7399 ...

  3. PHP 7.0 EOL (PHP 技术支持相关)

    PHP 7.0 EOL (PHP 支持相关) PHP 5.6 于 2018-12-31 结束(EOL) 从图表看出,PHP 7.0 是一个过渡版本,现在已经 EOL. 而 PHP 7.1 将于明年年底 ...

  4. C51 头文件中的 extern

    C51 头文件使用 extern 的目的是声明外部变量或函数. 使用注意: 只放在  .h 文件中. 声明时不用赋值. extern 只是声明不是定义.

  5. 虚拟机设置成桥接模式x86_openwrt也可以上网

    一.虚拟机桥接设置 1. 2.选择 虚拟机 >>设置 三.ip设置,要在同一网段,能够分配到路由的ip地址 1.主机ip 2.虚拟机中x86_openwrt ip 四.openwrt设置 ...

  6. MySQL性能指标及计算方法(go)

    绝大多数MySQL性能指标可以通过以下两种方式获取: (1)mysqladmin 使用mysqladmin extended-status命令获得的MySQL的性能指标,默认为累计值.如果想了解当前状 ...

  7. EINTR与ERESTARTSYS

    驱动中如果down_interruptible之类的函数被信号中断,驱动可以返回-EINTR或-ERESTARTSYS. 区别在于: 若返回-EINTR,应用程序执行的系统调用会返回表示错误的值,且e ...

  8. sql 查询年龄

    SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- ...

  9. ALGO-7_蓝桥杯_算法训练_逆序对

    出处:http://blog.csdn.net/enjoying_science/article/details/44114035 (有难度,以后回来填坑) 阅读代码中: #include<st ...

  10. 【Spring学习笔记-MVC-7】Spring MVC模型对象-模型属性讲解

    作者:ssslinppp       来自为知笔记(Wiz) 附件列表 处理模型数据.png