Python 面向对象之继承和组合

Python 面向对象之继承和组合

【一】继承

【1】概念

  • 继承是面向对象的三大特征之一
  • 继承允许一个类继承另一个类的属性
  • 继承可以使代码重用解决类与类之间代码重复的问题

【2】代码解释

  • 不使用继承,创建豌豆射手类和豌豆的双发射手类
# 豌豆射手类
class PeaShooter:
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value
        
    def twist_body(self):
        print(f"{self.name}在扭动身体")  

    def shoot(self):
        print(f"{self.name}发射了一颗豌豆")

# 双发射手类
class DoublePeaShooter:
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value
        
    def twist_body(self):
        print(f"{self.name}在扭动身体")  

    def shoot(self):
        print(f"{self.name}发射了两颗豌豆")
  • 可以看到这两个类之间有太多重复的内容了,所以使用在创建双发射手的时候使用继承
  • 可以直接继承他们的属性(名字和攻击力),继承方法(扭动身体的方法),重写方法(攻击)
class PeaShooter:
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value

    def twist_body(self):
        print(f"{self.name}在扭动身体")

    def shoot(self):
        print(f"{self.name}发射了一颗豌豆")


class DoublePeaShooter(PeaShooter):
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value

    # 同名覆盖父类方法
    def shoot(self):
        print(f"{self.name}发射了两颗豌豆")


plant_one = DoublePeaShooter("双发射手", 20)
print(plant_one.name)  # 双发射手
# 直接调用父类方法
plant_one.twist_body()  # 双发射手在扭动身体
# 调用重写的方法
plant_one.shoot()  # 双发射手发射了两颗豌豆
  • python支撑多继承,新建的类可以继承一个或者多个父类
  • 多继承的例子,我们来简单的写以下豌豆僵尸
  • 豌豆僵尸继承了豌豆射手类和僵尸类

请添加图片描述

class PeaShooter:
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value

    def shoot(self):
        print(f"{self.name}发射了一颗豌豆")


class Zombie:
    def __init__(self, name, health):
        self.name = name
        self.health = health

    def walk(self):
        print(f"{self.name}正在前进")


class ZombiePeashooter(Zombie, PeaShooter):
    def __init__(self, name, attack_value, health):
        self.name = name
        self.health = health
        self.attack_value = attack_value


special_zombies = ZombiePeashooter("豌豆射手僵尸", 20, 100)


print(special_zombies.name)  # 豌豆射手僵尸
print(special_zombies.health)  # 豌豆射手僵尸

# 继承父类的方法
special_zombies.shoot()  # 豌豆射手僵尸发射了一颗豌豆
special_zombies.walk()  # 豌豆射手僵尸正在前进

【3】经典类和新式类

  • 经典类:没有继承object类的所有子类
  • 新式类:继承了object类的子类
  • Python3中如果不写继承关系那么就将默认继承object类,所以**Python3里面都是新式类**

【二】实例属性查找顺序

【1】不存在隐藏属性(简单继承)

  • 先从自己的**__dict__**中查找
  • 然后从对象所在的类中查找
  • 然后去父类中查找
  • 最后去**object中查找,没有就要报错**了
class A:
    only1 = "在父类A"
    only2 = "在父类A"
    only3 = "在父类A"

class B(A):
    only1 ="在对象所在类B"
    only2 ="在对象所在类B"
    def __int__(self):
        self.only1 = "在实例化方法中"

b = B()
print(b.only1)  # 在对象所在类B
print(b.only2)  # 在对象所在类B
print(b.only3)  # 在父类A

【2】存在隐藏属性时(简单继承)

  • 父类的隐藏属性或者方法无法被子类查找到,因为属性或方法的变形发生在每个类的定义阶段,子类无法知道父类的属性或方法是否变形
class A:
    __only = "类A的私有属性"

    def __only_func(self):
        print("类A的私有方法")


class B(A):
    ...


b = B()
b.__only  # 报错,找不到
b.__only_func()  # 报错,找不到
  • 思考题:父类调用和子类同名的私有方法,这个会执行父类的还是子类的私有方法?
class A:
    def __only_func(self):
        print("类A的私有方法")
        self.__only_func()

    def run(self):
        print(self)
        self.__only_func()


class B(A):
    def __only_func(self):
        print("类B的私有方法")

  • 答案:会执行夫类的私有方法,因为此时父类中的self实例虽然是子类的实例,但是父类中的私有方法调用已经产生了变形,变形结果是父类的方法,所以会执行父类的私有方法
class A:
    def __only_func(self):
        print("类A的私有方法")

    def run(self):
        print(self)
        self.__only_func()


class B(A):
    def __only_func(self):
        print("类B的私有方法")

b = B()
b.run()
# <__main__.B object at 0x000001CF8D26AE90>
# 类A的私有方法

【三】继承顺序原理

【0】补充:广度优先搜索和深度优先搜索

请添加图片描述

(1)广度优先搜索
  • 广度优先搜索(BFS)是一种图形搜索算法,用于遍历或搜索图数据结构的所有节点。在广度优先搜索中,从图的起始节点开始,首先访问起始节点,然后依次访问其相邻节点,接着访问这些相邻节点的相邻节点,以此类推。
  • 个人总结,从起始节点开始一次遍历相邻的节点并保存这些节点的信息(这些节点的相邻节点),在遍历完其实节点的所有相邻节点以后,以起始节点遍历的第一个节点当作新的起始节点继续访问其相邻节点并保存信息,一次循环往复**(一层一层往外拨)**
  • 左边的视图,以G为起始节点遍历得到E和F,G遍历完以后遍历E的相邻节点得到C,然后遍历F的相邻节点得到D。。。所以顺序是**GEFCDAB**
  • 右边的视图,以F为起始节点遍历得到D和E,F遍历完以后遍历D的相邻节点得到A,然后遍历E的相邻节点得到C。。。所以顺序是**FDEACB**
(2)深度优先搜索
  • 深度优先搜索(DFS)是一种图形搜索算法,用于遍历或搜索图数据结构的所有节点。在深度优先搜索中,从图的起始节点开始,首先访问起始节点,然后沿着图的一条路径一直访问到最深的节点,直到无法继续深入为止,然后回溯到前一个节点,继续探索其他路径。
  • 个人总结,从起始节点开始沿着第一个相邻节点开始往下走,直到遇到岔路口是保存岔路信息,一次循环往复,直到走到底时,返回上一个分叉路口,走另一条路,继续循往复,最终按照这个总的逻辑循环执行**(一条路走到底返回继续一条路走到底)**
  • 左边的视图,以G为起始节点遍历时,是一个分叉路口,保存分叉路口信息,沿着第一个节点E开始遍历,由于后面是直线直接走到底,然后返回分叉路口信息,走另一个路口,所以顺序是**GECAFDB**
  • 右边的视图,以F为起始节点遍历时,是一个分叉路口,保存分叉路口信息,沿着第一个节点D开始遍历,由于后面是直线直接走到底,然后返回分叉路口信息,走另一个路口,所以顺序是**FDAECB**

请添加图片描述

(3)简单练习
  • 广度优先搜索(F出发):FCDEBA
  • 深度优先搜索(F出发):FCBADE

【1】类的继承顺序

(1)概念解释
  • 继承的顺序在python中是由C3线性化算法来确定的,也被称为C3算法
  • C3算法基本原则:
    • 线性化: 对于每个类,将其父类的线性化合并,再加上类本身,形成该类的线性化。
    • 合并: 在线性化的过程中,需要合并多个线性化的顺序。合并的规则是从左到右,依次取各个线性化中的第一个类,检查它在其他线性化中是否也位于第一个位置,如果是,就去掉这个类,继续检查下一个位置,直到找到一个不位于其他线性化首位置的类,将其添加到结果中。
  • 个人总结(理不理解都不重要):在不管object类的情况下(看着简单点),先将所有的砖石(菱形)继承关系处理(处理方法:砖石顶部先不管,将砖石身和砖石底部按照深度优先搜索遍历,遍历的结果变成一条直线放在该位置),在处理完所有砖石(菱形)继承关系以后,此时的继承关系图应该像树根一样最后按照深度优先搜索即可
  • 上述三个视图的继承关系
    • 视图1:GECAFDB
    • 视图2:FDAECB
    • 视图3:FCDBEA
  • 根据视图3结果:可以看到它既不是深度优先搜索不是广度优先搜索
(2)mro()方法查看继承顺序
  • 为什么上面说理不理解都不重要呢,因为可以使用**mro()方法直接得到继承继承顺序**
  • __mro__返回的是元组
  • mro()返回的是列表
# 以最复杂的视图3为例
# 创建继承关系

class A():
    pass
class B(A):
    pass
class C(B):
    pass
class D(B):
    pass
class E(A):
    pass

class F(C, D, E):
    pass

print(F.mro(), type(F.mro()))
print(F.__mro__, type(F.__mro__))
# [<class '__main__.F'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.A'>, <class 'object'>] <class 'list'>
# (<class '__main__.F'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.A'>, <class 'object'>) <class 'tuple'>
print("".join([i.__name__ for i in F.mro()]))
# FCDBEAobject

【4】派生

【1】概念

  • 派生通常指的是通过已经有的类创建新的类,新的类继承了已有类的特性(属性和方法),并且可以在此基础上太你家新的特性或修改已有的特性
  • 派生的方式有两种:
    • 第一种是通过类名显示调用父类的属性或方法(类名调用)
    • 第二种是使用super()隐式调用(函数super
      • super是给新式类用的
      • python2中使用super(类名,self).属性

【2】代码

class PeaShooter:
    def __init__(self, name, attack_value):
        self.name = name
        self.attack_value = attack_value

    def shoot(self):
        print(f"{self.name}发射了一颗豌豆")


class DoublePeaShooter(PeaShooter):
    def __init__(self, name, attack_value):
        #  重写
        # self.name = name
        # self.attack_value = attack_value
        # # 显示调用
        # PeaShooter.__init__(self, name, attack_value)
        # 隐式调用py2, py3环境无法执行
        # super(PeaShooter, self).__init__(name, attack_value)
        # 隐式调用py3
        super().__init__(name, attack_value)

    # 不写直接继承shoot方法

    def shoot(self):
        # 重写
        print(f"{self.name}发射了一颗豌豆")
        # # 显示调用
        # PeaShooter.shoot()
        # 隐式调用py2, py3环境无法执行
        # super(PeaShooter, self).shoot()
        # 隐式调用py3
        super().shoot()

【五】组合

【1】概念

  • 组合:组合是一种设计模式,它允许一个类包含其他类的对象,使得一个类的实例可以拥有其他类的对象,从而形成更加复杂的结构。
  • 在一个类中以另一个类的对象作为属性,称为类的组合
  • 组合和继承都是解决代码的重用性问题
    • 继承是一种的关系,谁是谁的
    • 组合是一种的关系,谁有谁

【2】代码演示

  • 将特殊豌豆这个类作为属性
class SpecialPea:
    def __init__(self, name, special_str):
        self.pea_name = name
        self.special_str = special_str

    def introduce_pea(self):
        print(f"我的特殊豌豆是{self.pea_name}, 功能是{self.special_str}")


class Peashooter:
    def __init__(self, name):
        self.name = name
        if "火焰" in name:
            self.pea = SpecialPea("火焰豌豆", "烧伤")
        elif "寒冰" in name:
            self.pea = SpecialPea("寒冰豌豆", "减速")


shooter1 = Peashooter("寒冰豌豆射手")
shooter2 = Peashooter("火焰豌豆射手")

print(shooter1.pea.pea_name)
shooter1.pea.introduce_pea()
# 寒冰豌豆
# 我的特殊豌豆是寒冰豌豆, 功能是减速
print(shooter2.pea.pea_name)
shooter2.pea.introduce_pea()
# 火焰豌豆
# 我的特殊豌豆是火焰豌豆, 功能是烧伤

【六】总结

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294814.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Golang】Json 无法表示 float64 类型的 NaN 以及 Inf 导致的 panic

【Golang】Json 无法表示 float64 类型的 NaN 以及 Inf 导致的 panic 原因 golang 服务出现了 panic&#xff0c;根据 panic 打印出的堆栈找到了问题代码&#xff0c;看上去原因是&#xff1a;json 序列化时&#xff0c;遇到了无法序列化的内容 [panic]: json: unsupported …

项目优化的方法

持续更新中… 目录 性能防抖、节流防抖(debounce)节流(throttle)防抖节流的区别&#xff1a; 图片/视频/音频压缩减少请求发送次数减少重绘与回流经常要切换消失与出现状态的节点用v-show而不用v-if按需引入路由懒加载懒加载图片懒加载列表懒加载 精灵/雪碧图Webpack优化前端性…

使用Go语言编写高效的HTTP服务器

随着互联网的快速发展&#xff0c;HTTP服务器在Web开发中扮演着越来越重要的角色。而Go语言作为一种高效、并发性强的编程语言&#xff0c;为编写高性能的HTTP服务器提供了强大的支持。本文将探讨如何使用Go语言编写高效的HTTP服务器。 首先&#xff0c;我们需要了解Go语言的H…

某大型电商APP sign头部签名逆向分析

APP版本 唯品会 7.45Java层抓包分析 打开抓包工具 charles进行分析&#xff0c;可以发现对于API采集需要突破当前这个参数&#xff0c;否则不返回信息 jadx静态分析 jadx静态分析&#xff0c;打开app搜索关键词api_sign&#xff0c;可以发现有参数位置 跟进去上边str赋值方…

三剑客前端教程

前端教程 结构层&#xff08;html&#xff09;表现层&#xff08;css&#xff09;行为层&#xff08;javascript&#xff09; HTML 超文本标记语言&#xff09; HTML&#xff08;超文本标记语言——HyperText Markup Language&#xff09;是构成 Web 世界的一砖一瓦。它定义…

LLM(九)| 使用LlamaIndex本地运行Mixtral 8x7大模型

欧洲人工智能巨头Mistral AI最近开源Mixtral 8x7b大模型&#xff0c;是一个“专家混合”模型&#xff0c;由八个70亿参数的模型组成。Mistral AI在一篇博客文章&#xff08;https://mistral.ai/news/mixtral-of-experts/&#xff09;介绍了Mixtral 8x7b&#xff0c;在许多基准上…

一致性算法Paxos

Paxos Paxos 算法解决的问题是一个分布式系统如何就某个值&#xff08;决议&#xff09;达成一致。一个典型的场景是&#xff0c;在一个分布式数据库系统中&#xff0c;如果各节点的初始状态一致&#xff0c;每个节点执行相同的操作序列&#xff0c;那么他们最后能得到一个一致…

如何实现任意文档的离线翻译且源文档格式不变?支持离线全自动翻译,无需改动页面、无语言配置文件、无API Key、对SEO友好!(附源码)

如何实现任意文档的离线翻译且源文档格式不变?支持离线全自动翻译,无需改动页面、无语言配置文件、无API Key、对SEO友好!(免费使用附所有源码) 在工作和生活中,是否遇到过这样的场景: 1)有些文档很长且不是自己擅长的语言,阅读起来很费力,需要把文档进行翻译之后再…

效果图渲染角度哪什么小技巧?

在创建效果图渲染时&#xff0c;正确设置相机角度对于表现设计的视觉效果至关重要。好的效果图通常能够增强设计图张力&#xff0c;通过效果图也能更好的看到真实物体的成果&#xff0c;以下是一些效果图渲染角度技巧&#xff0c;可以帮助你提高渲染的质量和表现力&#xff0c;…

软件测试|一篇文章带你深入理解SQL约束

深入理解SQL约束&#xff1a;保障数据完整性和一致性的重要工具 SQL约束是在关系型数据库中用于保障数据完整性和一致性的重要工具。本文将深入探讨SQL约束的概念、类型以及应用&#xff0c;以帮助读者更好地理解和使用SQL约束来确保数据库中的数据质量。 SQL约束 约束&…

Maven之依赖的传递

问题导入 1. 依赖传递 A依赖B&#xff0c;B依赖C&#xff0c;A是否依赖于C呢&#xff1f;–A依赖于C 依赖具有传递性 路径优先&#xff1a;当依赖中出现相同的的资源时&#xff0c;层级越深&#xff0c;优先级越低&#xff0c;层级越浅&#xff0c;优先级越高 声明优先&…

鸿蒙会不会像10几年前安卓一样,红极一时

如今&#xff0c;鸿蒙与安卓彻底切割时间似乎越来越近&#xff0c;一批嗅觉灵敏的互联网厂商已经完成或开始启动开发鸿蒙原生App。随着头部App厂商启动鸿蒙&#xff08;HarmonyOS&#xff09;原生应用开发&#xff0c;鸿蒙开发人才变得紧缺。专家预测&#xff0c;鸿蒙开发的人才…

通过聚道云软件连接器实现金蝶软件与客如云软件的无缝对接

客户介绍 某知名冷饮连锁品牌是国内一家拥有数千家门店的知名品牌&#xff0c;作为一家专注于冷饮和甜品的企业&#xff0c;我们致力于提供高品质、健康美味的食品&#xff0c;为消费者带来冰凉的甜蜜与畅快的口感。 我们始终坚持选用优质原料&#xff0c;严格把控生产流程&a…

数据库基础知识1

关系模型的程序员不需熟悉数据库的存取路径 在3层模式结构中,___I___是数据库的核心和关键,___Ⅱ___通常是模式的子集,数据库模式的描述提供给用户,____Ⅲ__的描述存储在硬盘上。Ⅰ.模式Ⅱ. 外模式Ⅲ. 内模式 数据库中,数据的物理独立性是指用户的应用程序与存储在磁盘上数据库…

数据库——SQL注入攻击

【实验内容及要求】 一、内容&#xff1a;掌握SQL注入攻击的原理&#xff0c;掌握基本SQL注入攻击的方法&#xff0c;掌握防SQL注入攻击的基本措施。 二、要求&#xff1a; 1. DVWA环境配置 DVWA&#xff08;Damn Vulnerable Web Application&#xff09;是一个用来进行安全…

使用ffmpeg+flv.js + websokect播放rtsp格式视频流

对于rtsp的视频流网上有很多种的解决方案&#xff0c;但是大的趋势还是利用ffmpeg的工具进行rtsp的视频解析进行一个推流&#xff0c;我最终选择bilibili开源的flv.js&#xff0c;代码十分的简单全部都在底层封装好了。实现的方式也比较容易理解&#xff0c;ffmpeg进行rtsp的视…

springboot、spring-kafka、kafka-client的版本对应关系

在使用springboot集成kafka的时候需要注意springboot版本、引用的依赖spring-kafka版本和kafka中间件版本的对应关系&#xff0c;否则可能会因为版本不兼容导致出现错误。 1、含义说明&#xff08;摘自官网&#xff09; Spring Boot&#xff1a;是springboot的版本。Spring fo…

【MLOps】使用Ray缩放AI

Ray正在人工智能工程领域崭露头角&#xff0c;对扩展LLM和RL至关重要 Spark在数据工程中几乎是必不可少的。Ray正在人工智能工程领域崭露头角。 雷是伦敦大学学院Spark的继任者。Spark和Ray有很多相似之处&#xff0c;例如用于计算的统一引擎。但Spark主要专注于大规模数据分析…

SSMBUG汇总

20240103 通用&#xff0c;驼峰命名法&#xff0c;mybatis。 mybatis入门程序中&#xff0c; // 获取对象的顺序为&#xff1a;SqlSessionFactoryBuild-》SqlSessionFactory-》SqlSessionSqlSessionFactoryBuilder sqlSessionFactoryBuilder new SqlSessionFactoryBuilder();I…

数字孪生与大数据和分析技术的结合

数字孪生与大数据和分析技术的结合可以为系统提供更深入的见解、支持实时决策&#xff0c;并优化模型的性能。以下是数字孪生在大数据和分析技术中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流…