Python趣味入门14:类的继承

这篇具有很好参考价值的文章主要介绍了Python趣味入门14:类的继承。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

小牛叔带你轻松飞越Python类的门槛

1. 大话继承

继承最好的示例竟然是病毒复制。类似于COVID-19病毒全球肆虐,病毒复制变异的过程就是下一代继承上一代部分特性,并发展出新特性的过程(如下图)。

病毒的变异来源于DNA(RNA)蛋白质突变

因此编程中的继承,也具有如下两个特征:

  1. 复制上一代的特性(即属性与方法)
  2. 发展出新特性(即属性与方法)

2. 层次性与复用

可以把类Class看成病毒(代码)的DNA,那么定义新的类(Class)就相当于产生了新病毒,而从类创建实例的过程,就类似于同病毒自我复制产生很多DNA相同的病毒体, 类的继承就相当于这个DNA在复制过程中产生了变异,产生了新的种类的病毒DNA或是病毒的变种的DNA的过程。

“继承”过程在程序中通常必须由程序来手工的显式声明(当然也不排除能自我复制变异的程序存在:-) ),假设我们正在给类似于王者荣耀的游戏做NPC的角色,为了重复利用角色的特性,我们可以把各种角色以层次关系进行组织,图中第个节点都是类:

游戏角色继承关系


在这样的继承关系里,所有的NPC都可以共享相同的底层逻辑:共享各种属性比如生命值,攻击能力(值是不同的但是名称相同);并且可以共享相同的行为(即方法)比如攻击,无论什么NPC攻击了就可以让对方减少生命值。

看上图的第二层,小兵继承自NPC,并且可以发展出自己的特性给下一层的Class重复使用。比如小兵可以增加“行走”这个行为(即方法),这个方法可以让小兵沿着兵线路径进行移动,无论什么兵都要共用这个行为。

3. 基本示例

下面我们就要实现上图两个类: NPC和Soldier,其关系如下图所示:

类中的各元素的继承关系

下面的代码实现上面的类的继承,先定义最基本的NPC类和Soldier类如下:

 1 class Npc:
 2 
 3     def __init__(self,name):   #初始化方法 self(方法的第1个位置参数)代表这个类的实例
 4         self.name = 'NPC' #初始名称为NPC
 5         self.life = 100   #生命值初始为100
 6         self.harm = 2     #伤害初始为2
 7 
 8     def __str__(self):    #实例转成字符串时返回的字符串值
 9         return '%s %d'%(self.name,self.life)  #返回这个类的实例时就打印名称和生命值
10 
11     def attack(self,other): #攻击使别人生命值下降,把“别人”(other)当成参数传进来
12         print(self.name,'攻击',other.name,'-%d'%self.harm)
13         other.life -= self.harm
14 
15 
16 class Soldier(Npc):
17     def __init__(self,name):
18         super().__init__(name)      #调用上层的初始化函数,使用父类的初始化代码
19         self.name = name            #士兵的名称
20     
21  

 

从Npc类的定义(参考前文介绍的类的定义)分析,明显可以看到这个类有3个属性分别是life(生命值)、harm(伤害力)和name(名称)并且有攻击行为(方法)。

继承语法:子类士兵定义时直接在类名士兵(Soldier)后使用括号即可,该类没有产生新的属性,只是使用传入的名称覆盖了原来的name属性。大家注意如下的表达式:

        super().__init__(name)          #调用上层的初始化函数,使用父类的初始化代码

 

表达式super()指的是父类的列表,这个语句就是调用父类Npc的初始化函数,这就显式地继承了NPC的3个属性:life(生命值)、harm(伤害力)和name(名称)。在其它情况下如果父类还有父类就会以MRO的顺序来排列。下面有文章是专门讲MRO的,可以参考:

岳星:Python super() 函数58 赞同 · 9 评论文章

4.重用父类方法

在上面Soldier类中没有定义attack(攻击)方法,而attack是定义在其父类Npc中的,那么我们可不可以直接在子类中使用呢?添加并运行如下的代码:

soldier_a = Soldier('红方兵')  #实例化士兵a
soldier_b = Soldier('蓝方兵')  #实例化士兵b
soldier_a.attack(soldier_b)   #使用了父类attack的方法
print(soldier_a,soldier_b)    #打印攻击的效果

 

上述代码在游戏当中产生了红蓝两方的士兵,并且通过初始化方法传入了名称,并且通过实例调用了attack方法,如果这个方法起作用的话,那么其中被攻击的蓝方兵应该生命值下降。把整个程序一起运行,看到如下的结果:

红方兵 攻击 蓝方兵 -2
红方兵 100 蓝方兵 98

可以看到无需要任何设置,子类可以直接使用父类的方法,但是子类必须通过重构__init()__这个函数,并且在函数中使用super()方法来,创建父类通过_init()__创建的实例属性。

5. 重构其它方法

Soldier子类完全重用了父类的attack方法,实际上也重构了父类的__init()__函数,以获得父类的属性。你作为游戏设计者,觉得这种“攻击”太普通了,想设计更酷炫的“攻击”,这就需要通过重构attack方法,来增加新的特性。

为了让读者更加了解方法的重构,我们假设“超级兵”自带“反甲”,即在受到攻击时自己受伤的同时,会让对方损失生命值。我们通过继承Soldier类来看看这个“超级兵”的attack怎么写?从NPC -> 兵 -> 超级兵 ,继承的关系如下图:

多级继承类中各元素的继承关系

继续添加并运行如下的代码:

class SuperSoldier(Soldier):
    def __init__(self,name):
        self.armHarm = 1                 #反甲伤害
        super().__init__(name)           #调用上层的初始化函数,使用父类的初始化代码
    
    def attack(self,other):
        super().attack(other)        #调用上层的攻击函数,重用父类的普通攻击行为
        if other.armHarm:
            self.life -= other.armHarm
            print(other.name, '有反甲受伤:',other.armHarm)

super_a = SuperSoldier('超级兵A')  #实例化带反甲的超级兵
super_b = SuperSoldier('超级兵B')  #实例化带反甲的超级兵
super_b.attack(super_a)           #超级B攻击A
print(super_a,super_b)   

 

上述代码给超级兵增加了反甲伤害的属性,并且重写了attack代码,运行后,结果如下:

超级兵B 攻击 超级兵A -2
超级兵A 有反甲受伤: 1
超级兵A 98 超级兵B 99

可以看出超级兵B虽然攻击了A但是自己也受了1点的伤害。通过在类中对父类定义的函数进行重构,并且结合super()函数,我们即可以重用老特性也可以为下一代增加新特性。

6. 多类继承

多类继承即有多个父类,这样就可以综合多个类的特性。 在王者里,已方战胜大龙,在我方兵线里会产生一种生物叫主宰先锋,如下所示它即有着兵的通常属性比如走路路线、生命值、攻击力,也有着龙(野怪)的喷火攻击方式。

多类继承能实现合体的效果

新建文件,复制粘贴下面全部的代码:

class Npc:

    def __init__(self,name):   #初始化方法 self(方法的第1个位置参数)代表这个类的实例
        self.name = 'NPC' #初始名称为NPC
        self.life = 100   #生命值初始为100
        self.harm = 2     #伤害初始为2

    def __str__(self):    #实例转成字符串时返回的字符串值
        return '%s %d'%(self.name,self.life)  #返回这个类的实例时就打印名称和生命值

    def attack(self,other): #攻击使别人生命值下降,把“别人”(other)当成参数传进来
        print(self.name,'攻击',other.name,'-%d'%self.harm)
        other.life -= self.harm


class Soldier(Npc):
    def __init__(self,name):
        super().__init__(name)          #调用上层的初始化函数,使用父类的初始化代码
        self.name = name            #士兵的名称
    
    def move(self):
        print(self.name,'走路','.'*20)  #用打出一个点代表移动

class Beast(Npc):
    def __init__(self,name):
        super().__init__(name)          #调用上层的初始化函数,使用父类的初始化代码
        self.name = name

    def fire(self):
        print(self.name,'喷火','*'*20)


class Pioneer(Soldier,Beast):
    def __init__(self,name):
        super().__init__(name)          #调用上层的初始化函数,使用父类的初始化代码


p = Pioneer('主宰先锋1')
print(p)
p.move()
p.fire()

 

运行之后看到运行结果:

主宰先锋1 100
主宰先锋1 走路 ....................
主宰先锋1 喷火 ********************

通过继承两个类,这个主宰先锋即有了走路的功能(只在父类Soldier中有定义),也有了喷火的功能(只在父类Beast中有定义),并且具有最原始的NPC的各种属性。

以上就是本篇类对象继承的内容,类的最核心的概念还是复用,一般高手写程序时都是从最抽象的类的开始写,把最容易共用的代码先写好,自顶向下的写程序。

小牛叔写文画画都不易,记得点赞。

本节的继承,如果您看得开心,记得分享给其它小朋友哦。文章来源地址https://www.toymoban.com/news/detail-768252.html

到了这里,关于Python趣味入门14:类的继承的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python面向对象编程(一)类的基础,关系,继承,封装,多态

    类的一些理论概念及其应用场景等基础内容此处不赘述 目录 python中一切皆对象 类的定义及基础 属性 方法 初始化方法  普通方法 类之间的关系 相互调用 依赖关系 关联关系 组合关系 三大特征----类的继承 重写父类方法 多继承 混合继承  三大特征----封装 三大特征----多态

    2024年02月10日
    浏览(79)
  • Python 中多态性的示例和类的继承多态性

    单词 \\\"多态\\\" 意味着 \\\"多种形式\\\",在编程中,它指的是具有相同名称的方法/函数/操作符,可以在许多不同的对象或类上执行。 一个示例是 Python 中的 len() 函数,它可以用于不同的对象。 对于字符串,len() 返回字符的数量: 示例 对于元组,len() 返回元组中项的数量: 示例 对

    2024年02月08日
    浏览(33)
  • Python趣味算法入门 - 百钱百鸡

    问题描述 中国古代数学家张邱建在他的《算经》中提出了一个著名的“百钱百鸡问题”:一只公鸡值五钱,一只母鸡值三钱,三只小鸡值一钱,现在要用百钱买百鸡,请问公鸡、母鸡、小鸡各多少只? 分析 这也是经典问题了,在数学上其实不过就是多元一次方程组。如果用

    2024年02月06日
    浏览(43)
  • Python趣味入门12:初遇类与实例

    小牛叔用轻松有趣的故事,带你进入Python的编程世界。 一提到类大神们就经常说封装。说白了,封装即把围绕同一个对象相同的代码、数据整合在一起。比如在某段游戏代码中(比如熊猫厨房),有一个“面包”: 1、游戏提供“烘烤”的操作。 - 很明显这是动作 - 类的方法

    2024年02月04日
    浏览(50)
  • Python趣味入门13:类中的各种变量

    其中我们已知道定义变量在类中就表示为属性。但是在不同的位置定义变量会有不同的作用,并且采用不同的命名方式,也会让变量具有不同的作用 本文假设有一个类指南针(compass),可想象成某个地图游戏中帮助主角寻找方向,也是本节主要的示例。 compass类的定义如下代

    2024年02月04日
    浏览(43)
  • Python趣味入门11:函数作为参数以及匿名函数

    Python里可以把函数本身当成是参数,比如Python内置函数map可以通过传入的函数返回值来一一映射列表集合里的元素,我们也可以在定义函数时,以调用函数的方式使用参数。 假设有一个列表1至9共有9个元素,现在需要求其平方数列。 map函数的示例   以上的代码,主要完成了

    2024年02月04日
    浏览(48)
  • Spring Boot入门(14):使用Mybatis-Plus轻松实现高效自定义SQL操作!

            在上几期,我们既讲了如何整合Mybatis-Plus进行数据库的增删改查,也讲解了如何使用MP的 Wrapper 构造器,但若是遇到复杂业务逻辑,如多表联查、动态拼接条件等,这些操作往往会让代码变得冗长且难以维护。但是,有了Mybatis-Plus这个优秀的框架,我们可以轻松实现

    2024年02月10日
    浏览(44)
  • C++ 类的继承

    class 子类名 :继承方式  父类名 继承方式:public:  protected: private: 特点:         不管哪种方式继承,都不印象子类对父类成员的访问权限,即除了private成员其他都可访问;         类外只能访问public方式继承的父类的公共区成员。

    2024年02月10日
    浏览(33)
  • 继承类的方法

    1 问题 定义一个父类,用子类去继承父类所拥有的方法、定义属性,然后使用测试文件实现子类输出父类的方法信息,属性等。 2 方法 2.1 定义一个名为Person的父类: 2.2 定义一个名为Student的子类,并令其继承父类: 2.3 定义父类的属性、方法: 2.4定义子类的属性,以及输出

    2024年02月08日
    浏览(38)
  • 第十九章 类的继承

    面向对象三大特点:封装,继承,多态 封装:打包 继承:一个对象A不具有某个功能a,通过某种方式使用了对象B的a功能 的过程 多态:对象或功能的多种形态,在使用某个对象时,不关心从哪来,在封装某个对象时,不关心将要在哪被使用 继承 构造函数执行之后得到的实例

    2024年02月01日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包