继承

什么是继承?就是一个派生类(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. Char.IsDigit与Char.IsNumber的区别

    需要判断Char是否为数字,查看了下MSDN,发现有三种方法: Char.IsDigit (aChar)              指示指定字符串中位于指定位置处的字符是否属于十进制数字类别 Char ...

  2. /etc/bashrc

    [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\[\e[34;1m\]\u@\[\e[0m\]\[\e[3 ...

  3. PostgreSQL中的The Oversized-Attribute Storage Technique(TOAST:超大属性存储技术)

    PostgreSQL使用固定的页面大小(通常为8kB),并且不允许元组跨越多个页面.因此,不可能直接存储非常大的字段值.为了克服这种限制,将大字段值压缩和/或分解成多个物理行.这对用户来说是透明的,对 ...

  4. openresty开发系列33--openresty执行流程之3重写rewrite和重定向

    openresty开发系列33--openresty执行流程之3重写rewrite和重定向 重写rewrite阶段 1)重定向2)内部,伪静态 先介绍一下if,rewrite指令 一)if指令语法:i ...

  5. 【IoT】物联网NB-IoT之电信物联网开放平台对接流程浅析

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/liwei16611/article/de ...

  6. 【Linux】使用 walle + docker-compose 部署上线单获取不到分支的解决办法

    背景: 使用walle+docker 自动化部署项目.在新建上线单时候拉取不到分支,并提示有错误.但是没有错误信息 错误排查: 首先确保远程仓库已添加宿主机公钥,且一定先在宿主机手动连接一下远程仓库, ...

  7. NB-IOT技术学习问题记录

    1. TAU是什么,跟踪区更新 2. 小区和基站的区别 3. 附着和设备注册的关系? 4. 不携带PDN是什么意思? 5. PLMN 公共陆地移动网络,和小区的关系,区别?

  8. Legacy和UEFI,MBR和GPT的区别

    Legacy(历史的,遗留的,传统的)和UEFI指的是系统引导方式(Legacy为传统BIOS,UEFI为新式BIOS),MBR和GPT指的是磁盘分区表类型. 一般情况下都是Legacy+MBR, U ...

  9. Rufus软件

    Rufus软件(https://rufus.akeo.ie/)——制作启动盘必备,简易且开源.

  10. (一)Python的特点(优点和缺点)

    Python 是一种面向对象.解释型的脚本语言,同时也是一种功能强大而完善的通用型语言.相比其他编程语言(比如 Java),Python 代码非常简单,上手非常容易. Python优点: (1)简单易 ...