Python学习日记(二十四) 继承
继承
什么是继承?就是一个派生类(derived class)继承基类(base class)的字段和方法。一个类可以被多个类继承;在python中,一个类可以继承多个类。
父类可以称为基类和超类,而子类可以称为派生类
在继承中可分为单继承和多继承两种
下面是继承的用法,语法为'class 子类的名字(父类名):'
class Plane: #定义一个所有战机的父类def __init__(self,name,speed,hp,atk):self.name = nameself.speed = speedself.hp = hpself.atk = atkclass Fighter(Plane): #定义一个Fighter类 它继承的是Plane类def __init__(self,name,speed,hp,atk,money):self.name = nameself.speed = speedself.hp = hpself.atk = atkself.money= moneydef Attack(self,enemyFighter):enemyFighter.hp -= self.atkclass EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类def __init__(self,name,speed,hp,atk,type):self.name = nameself.speed = speedself.hp = hpself.atk = atkself.type = typedef 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 = nameself.speed = speedself.hp = hpself.atk = atkclass Fighter(Plane): #定义一个Fighter类 它继承的是Plane类def __init__(self,name,speed,hp,atk,money):Plane.__init__(self,name,speed,hp,atk) #这里的self是Fighter的selfself.money= money #派生属性def Attack(self,enemyFighter):enemyFighter.hp -= self.atkclass EnemyFighter(Plane): #定义一个EnemyFighter类 它继承的是Plane类def __init__(self,name,speed,hp,atk,type):Plane.__init__(self,name,speed,hp,atk) #这里的self是EnemyFighter的selfself.type = type #派生属性def EnemyAttack(self,fighter):fighter.hp -= self.atkf1 = 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 = nameself.speed = speedself.hp = hpself.atk = atkdef 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的selfself.money= money #派生属性def Attack(self,enemyFighter):enemyFighter.hp -= self.atkprint('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的selfself.type = type #派生属性def EnemyAttack(self,fighter):fighter.hp -= self.atkprint('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的selfself.money= money #派生属性def Attack(self,enemyFighter):Plane.Attack(self) #如果既想实现新的功能也想使用父类原本的功能,还需要在子类中调用父类enemyFighter.hp -= self.atkprint('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 = nameself.speed = speedself.hp = hpself.atk = atkdef 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的selfself.money= money #派生属性def Attack(self,enemyFighter):Plane.Attack(self) #如果既想实现新的功能也想使用父类原本的功能,还需要在子类中调用父类enemyFighter.hp -= self.atkprint('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的selfself.type = type #派生属性def EnemyAttack(self,fighter):Plane.Attack(self)fighter.hp -= self.atkprint('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它的本质不是单纯找父类,而是根据调用者的节点位置的广度优先顺序来找的
具体执行流程:
转载于:https://www.cnblogs.com/Fantac/p/11477508.html
Python学习日记(二十四) 继承相关推荐
- Python学习日记(三十四) Mysql数据库篇 二
外键(Foreign Key) 如果今天有一张表上面有很多职务的信息 我们可以通过使用外键的方式去将两张表产生关联 这样的好处能够节省空间,比方说你今天的职务名称很长,在一张表中就要重复的去写这个职务 ...
- Python学习日记-第十四天-面向对象练习
前言 今天主要是针对昨天学习的面向对象,进行两个练习. 一个是添加家具的练习 另一个是士兵开枪的练习 练习1: 添加家具 需求: 1. 房子 house 有户型,总面积和家具名称列表 ·新房子没有 ...
- Python学习日记(二十八) hashlib模块、configparse模块、logging模块
hashlib模块 主要提供字符加密算法功能,如md5.sha1.sha224.sha512.sha384等,这里的加密算法称为摘要算法.什么是摘要算法?它又称为哈希算法.散列算法,它通过一个函数把任 ...
- Python学习日记(二十二) 初识面向对象
引子 假设我们要开发一个关于飞机大战的游戏,那么游戏的里面就会有两个角色,分别是属于玩家操控的战机和敌方的战机,并且两个战机都有不同的技能或攻击方式,现在我们用自己目前所学的去写出下面的这些代码: d ...
- Python学习日记(二十五) 接口类、抽象类、多态
接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子 ...
- Python学习日记-第二十四天-飞机大战(敌机出场设计)
系列文章目录 ·使用定时器添加敌机 ·设计Enemy 类 前言 昨天因为有事,所以没有及时更新 一.使用定时器添加敌机 游戏启动后,每隔一秒会出现一架敌机 每架敌机向屏幕下方飞行,飞行速度各不相同 每 ...
- Python学习日记(二十六) 封装和几个装饰器函数
封装 广义上的封装,它其实是一种面向对象的思想,它能够保护代码;狭义上的封装是面向对象三大特性之一,能把属性和方法都藏起来不让人看见 私有属性 私有属性表示方式即在一个属性名前加上两个双下划线 cla ...
- Python学习日记(二十九) 网络编程
早期的计算机通信需要有一个中间件,A要给B传东西,A必须要把信息传给中间件,B再把从中间件中拿到信息 由于不同机器之间需要通信就产生了网络 软件开发的架构 1.C/S架构 服务器-客户机,即Clien ...
- 【Python学习系列二十四】scikit-learn库逻辑回归实现唯品会用户购买行为预测
1.背景:http://www.datafountain.cn/#/competitions/260/intro DataFountain上的唯品会用户购买行为预测比赛题目,笔者用逻辑回归实现,分数是 ...
最新文章
- 关于自动驾驶车安全保证、验证和认证的综述
- 微软获GPT-3独家授权,OpenAI创始人马斯克:与初衷相悖
- 连接的管道(最小生成树)
- 什么是TCP和UDP?—Vecloud微云
- MPU6050姿态融合(转载)
- 超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?
- H.264(MPEG-4 AVC)级别(Level)、DPB 与 MaxDpbMbs 详解(转载)
- Microsoft将Linux带至桌面操作系统
- 解决SpringBoot多模块发布时99%的问题?SpringBoot发布的8个原则和4个问题的解决方案
- 封装 java 1614782839
- Redis中的管道有什么用?
- HEAP: Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed
- UVa 10570 - Meeting with Aliens
- 手把手教你搭建Pytest+Allure2.X环境详细教程 - 01
- [Teamcenter 2007 开发系列] web 非空验证
- php mysql闪退_别批:mysql闪退问题如何解决??
- 创业关于抖音的技术分析与同类产品如何弯道超车的几个问题
- 老K仿真的惊人发现|社会的阶层分化过程
- 3步上架iOS APP【2022最新教程】
- windows 时间同步工具软件