继承

什么是继承?就是一个派生类(derived class)继承基类(base class)的字段和方法。一个类可以被多个类继承;在python中,一个类可以继承多个类。

父类可以称为基类和超类,而子类可以称为派生类

在继承中可分为单继承和多继承两种

下面是继承的用法,语法为'class 子类的名字(父类名):'

class Plane:                                    #定义一个所有战机的父类
def __init__(self,name,speed,hp,atk):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk class Fighter(Plane): #定义一个Fighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,money):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk
self.money= money
def Attack(self,enemyFighter):
enemyFighter.hp -= self.atk class EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,type):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk
self.type = type
def EnemyAttack(self,fighter):
fighter.hp -= self.atk

我们如果想知道一个类的父类是谁,可以使用__bases__方法查看

print(Plane.__bases__)          #(<class 'object'>,)
print(Fighter.__bases__) #(<class '__main__.Plane'>,)
print(EnemyFighter.__bases__) #(<class '__main__.Plane'>,)

可以从结果看出两个子类都继承了Plane这个父类,而Plane类它继承的是类的'祖宗'object类。在一个python3里所有的类都有父类,如果一个类它没有发生继承那么它的父类就是object的子类。

新式类:没有继承父类默认继承object类

抽象的概念

抽象就是抽取类似或比较像的部分

分为两个层次:将两个比较相似的对象比较像的部分抽取成类和把多个类比较像的部分抽取成父类

继承是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式表达出抽象的结构;且类与类之间才有继承的关系

单继承

我们在写上面的代码时候可以发现Fighter类和EnemyFighter类中有很多属性在父类都是重复的,并且有些属性又是自己特有的,那么对于这个派生类特有的属性我们称为派生属性。下面我们修改我们上面的代码:

class Plane:                                    #定义一个所有战机的父类
def __init__(self,name,speed,hp,atk):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk class Fighter(Plane): #定义一个Fighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,money):
Plane.__init__(self,name,speed,hp,atk) #这里的self是Fighter的self
self.money= money #派生属性
def Attack(self,enemyFighter):
enemyFighter.hp -= self.atk class EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,type):
Plane.__init__(self,name,speed,hp,atk) #这里的self是EnemyFighter的self
self.type = type #派生属性
def EnemyAttack(self,fighter):
fighter.hp -= self.atk f1 = Fighter('player1',150,1000,100,500)
print(f1.__dict__) #{'name': 'player1', 'speed': 150, 'hp': 1000, 'atk': 100, 'money': 500}
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
print(Boss1.__dict__) #{'name': 'AKS-89', 'speed': 50, 'hp': 3000, 'atk': 500, 'type': 'BOSS'}

现在给Plane类添加一个方法Attack,当如果子类和父类的方法重名时,在子类在调用的时候,如果子类中有这个名字那么就一定是用子类的,子类没有才找父类的,如果父类没有就报错

class Plane:                                    #定义一个所有战机的父类
def __init__(self,name,speed,hp,atk):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk
def Attack(self):
print(self.name+'发射子弹!') class Fighter(Plane): #定义一个Fighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,money):
Plane.__init__(self,name,speed,hp,atk) #这里的self是Fighter的self
self.money= money #派生属性
def Attack(self,enemyFighter):
enemyFighter.hp -= self.atk
print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp)) class EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,type):
Plane.__init__(self,name,speed,hp,atk) #这里的self是EnemyFighter的self
self.type = type #派生属性
def EnemyAttack(self,fighter):
fighter.hp -= self.atk
print('Now {0} hp : {1}'.format(fighter.name, fighter.hp)) f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS') f1.Attack(Boss1) #Now AKS-89 hp : 2900
Boss1.EnemyAttack(f1) #Now player1 hp : 500
Boss1.Attack() #AKS-89发射子弹!

派生方法:父类中没有但在子类中特有的方法,例如上面的EnemyAttack()

如果一个子类还想用父类的东西,应该单独调用父类的

<1>父类名.类方法名(self参数),这里的self参数必须传

class Fighter(Plane):                           #定义一个Fighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,money):
Plane.__init__(self,name,speed,hp,atk) #这里的self是Fighter的self
self.money= money #派生属性
def Attack(self,enemyFighter):
Plane.Attack(self) #如果既想实现新的功能也想使用父类原本的功能,还需要在子类中调用父类
enemyFighter.hp -= self.atk
print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp))
f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
f1.Attack(Boss1) #player1发射子弹!
#Now AKS-89 hp : 2900

<2>super方法

class Plane:                                    #定义一个所有战机的父类
def __init__(self,name,speed,hp,atk):
self.name = name
self.speed = speed
self.hp = hp
self.atk = atk
def Attack(self):
print(self.name+'发射子弹!') class Fighter(Plane): #定义一个Fighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,money):
super().__init__(name,speed,hp,atk) #这里的self是Fighter的self
self.money= money #派生属性
def Attack(self,enemyFighter):
Plane.Attack(self) #如果既想实现新的功能也想使用父类原本的功能,还需要在子类中调用父类
enemyFighter.hp -= self.atk
print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp)) class EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类
def __init__(self,name,speed,hp,atk,type):
super().__init__(name,speed,hp,atk) #这里的self是EnemyFighter的self
self.type = type #派生属性
def EnemyAttack(self,fighter):
Plane.Attack(self)
fighter.hp -= self.atk
print('Now {0} hp : {1}'.format(fighter.name, fighter.hp)) f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
f1.Attack(Boss1) #player1发射子弹!
#Now AKS-89 hp : 2900
Boss1.EnemyAttack(f1) #AKS-89发射子弹!
#Now player1 hp : 500

super()函数在这里省略了两个参数,分别是子类名和self参数。super()只在新式类有并且它只在python3存在,而在python3中所有的类都是新式类。对于单继承来说super()就可以找到他的父类了;上面的super()用法是在类的内部使用。

super()在类的外部使用:

f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
super(Fighter,f1).Attack() #player1发射子弹!
super(EnemyFighter,Boss1).Attack() #AKS-89发射子弹!

可以直接找父类的这一个函数并进行调用

在单继承中,一个类它只继承一个基类且一般来说它能够减少代码的重复,提高代码可读性,规范编程模式

多继承

多继承顾名思义就是一个类它继承了两个或两个以上的父类

<1>钻石继承:

假设有4个类它们的继承关系如下图表示

class A:
def fuc(self):
print('A')
class C(A):
def fuc(self):
print('C')
class D(A):
def fuc(self):
print('D')
class B(C,D):
def fuc(self):
print('B')
b = B()
b.fuc() #B

第一次执行fuc

如果把B类的方法注释掉现在的结果是什么?

class A:
def fuc(self):
print('A')
class C(A):
def fuc(self):
print('C')
class D(A):
def fuc(self):
print('D')
class B(C,D):
pass
# def fuc(self):
# print('B')
b = B()
b.fuc() #C

第二次执行fuc

再注释掉C类的方法

class A:
def fuc(self):
print('A')
class C(A):
pass
# def fuc(self):
# print('C')
class D(A):
def fuc(self):
print('D')
class B(C,D):
pass
# def fuc(self):
# print('B')
b = B()
b.fuc() #D

第三次执行fuc

所以在最后一次执行的结果就是A了

我们也可以通过B.mro()的方法来知道python是怎么走的

class A:
def fuc(self):
print('A')
class C(A):
def fuc(self):
print('C')
class D(A):
def fuc(self):
print('D')
class B(C,D):
def fuc(self):
print('B')
b = B()
print(B.mro()) #[<class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]

结果

在这里为什么先找的是D而不是A呢?虽然python在找的时候它其实已经知道了C后面有一个A,但是它要优先遵循从左往右的方向去找并且C->A,D->A,如果它直接找到A的话那么D的节点就会丢失,如果一个节点丢失的话就再也找不回来了,所以第三次结果它打印了D。

<2>乌龟继承:

这些类的继承关系如下图表示

class A:
def fuc(self):
print('A')
class B(A):
def fuc(self):
print('B')
class F(A):
def fuc(self):
print('F')
class C(B):
def fuc(self):
print('C')
class E(F):
def fuc(self):
print('E')
class D(E,C):
def fuc(self):
print('D')
print(D.mro())
#[<class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

这种记录继承顺序它是新式类的继承顺序,所遵循的是广度优先

而在python2.7中就是经典类,它所遵循的深度优先即走过的路就不走了,在这里的结果就是D->E->F->A->C->B

总结:

如果是多个父类中有一个方法的名字都相同,一个子类继承了这些父类,当它去用这个方法的时候,它会优先从左往右去找

python2.7 新式类和经典类共存,新式类要继承object

python3 只有新式类,默认继承object

经典类和新式类还有一个区别就是mro方法之在新式类存在

super的本质

用到上面钻石继承的继承关系图,但代码稍微改动

class A:
def fuc(self):
print('A')
class C(A):
def fuc(self):
super().fuc()
print('C')
class D(A):
def fuc(self):
super().fuc()
print('D')
class B(C,D):
def fuc(self):
super().fuc()
print('B')
b = B()
b.fuc()
# A
# D
# C
# B

super它的本质不是单纯找父类,而是根据调用者的节点位置的广度优先顺序来找的

具体执行流程:

Python学习日记(二十四) 继承的更多相关文章

  1. Python学习日记(三十四) Mysql数据库篇 二

    外键(Foreign Key) 如果今天有一张表上面有很多职务的信息 我们可以通过使用外键的方式去将两张表产生关联 这样的好处能够节省空间,比方说你今天的职务名称很长,在一张表中就要重复的去写这个职务 ...

  2. Python学习日记(二十八) hashlib模块、configparse模块、logging模块

    hashlib模块 主要提供字符加密算法功能,如md5.sha1.sha224.sha512.sha384等,这里的加密算法称为摘要算法.什么是摘要算法?它又称为哈希算法.散列算法,它通过一个函数把任 ...

  3. Python学习(二十四)—— 前端基础之Bookstrap

    转载自:http://www.cnblogs.com/liwenzhou/p/8214637.html 一.Bootstrap介绍 Bootstrap是Twitter开源的基于HTML.CSS.Jav ...

  4. Python学习日记(二十五) 接口类、抽象类、多态

    接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子 ...

  5. Python学习日记(二十二) 初识面向对象

    引子 假设我们要开发一个关于飞机大战的游戏,那么游戏的里面就会有两个角色,分别是属于玩家操控的战机和敌方的战机,并且两个战机都有不同的技能或攻击方式,现在我们用自己目前所学的去写出下面的这些代码: d ...

  6. Python学习札记(二十四) 函数式编程5 返回函数

    参考:返回函数 NOTE 1.高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. eg.求和函数 #!/usr/bin/env python3 def calsums(*args): a ...

  7. Python学习日记(二十九) 网络编程

    早期的计算机通信需要有一个中间件,A要给B传东西,A必须要把信息传给中间件,B再把从中间件中拿到信息 由于不同机器之间需要通信就产生了网络 软件开发的架构 1.C/S架构 服务器-客户机,即Clien ...

  8. Python学习日记(二十六) 封装和几个装饰器函数

    封装 广义上的封装,它其实是一种面向对象的思想,它能够保护代码;狭义上的封装是面向对象三大特性之一,能把属性和方法都藏起来不让人看见 私有属性 私有属性表示方式即在一个属性名前加上两个双下划线 cla ...

  9. python学习(二十四) 字符串格式化

    1: Test 1 a = 'city' b = 'country' print(" aaa %s bbb %s " % (a, b)) result: aaa city bbb ...

随机推荐

  1. jsoup获取标签下的文本(去除子标签的)

    jsoup获取标签下的文本(去除子标签的) <pre name="code" class="java">Element content=doc.se ...

  2. 命令mark

    for i in `sudo /usr/local/sbin/fping -g 10.181.37.0/26 -p 10 -r 1 | grep alive | awk '{print $1 }'`; ...

  3. 查询、下载GWAS目录数据的R包(gwasrapidd)

    目前GWAS方向发了很多文献,但是并没有一个很完善的R包对这些文献的数据进行汇总. 接下来推荐的这个是最新发表的GWAS数据汇总R包​.看了一下功能齐全,但是数据不是收录的很齐全​. 下面具体讲一下. ...

  4. VC++6.0/VC6使用c99的stdint.h

    如果使用https://github.com/mattn/gntp-send/blob/master/include/msinttypes/stdint.h会报错: error C2733: seco ...

  5. [LeetCode] 165. Compare Version Numbers 比较版本数

    Compare two version numbers version1 and version1.If version1 > version2 return 1, if version1 &l ...

  6. Java之变量和数据类型

    变量 什么是变量 变量就是初中的代数的概念.例如一个简单的方程,x,y都是变量 y=x+1 在Java中,变量分为两种:基本类型的变量和引用类型的变量 在Java中,变量必须先定义后使用,在定义变量的 ...

  7. js arguments

    偶然碰见一个有意思的题 <script> var length = 10; function fn() { console.log( this.length ); // 10 } var ...

  8. python文件夹操作

    1.遍历文件夹下所有文件2.将后缀为.DCM的文件复制到指定文件夹 import os import shutil def all_path(dirname): result = []#所有的文件 f ...

  9. XML解析详解|乐字节

    大家好,乐字节的小乐又来了,Java技术分享哪里少的了小乐!上次我们说了可扩展标记语言XML之二:XML语言格式规范.文档组成,本文将介绍重点——XML解析.   基本的解析方式有两种:一种叫 SAX ...

  10. laydate 只设置年月日,时分,不设置秒

    laydate.render({ elem: '#deadline_time' ,type: 'datetime' ,format: 'yyyy-MM-dd HH:mm' }); 设置了format, ...