Python 面向对象之继承和组合

news2024/12/28 19:40:50

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()
# 火焰豌豆
# 我的特殊豌豆是火焰豌豆, 功能是烧伤

【六】总结

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言编译器(C语言编程软件)完全攻略(第六部分:VS2017下载地址和安装教程(图解))

介绍常用C语言编译器的安装、配置和使用。 六、VS2017下载地址和安装教程&#xff08;图解&#xff09; 继vs2015版本后&#xff0c;微软又推出了功能更加强大的VS 2017。 Visual Studio 2017 不仅支持 C#、C、Python、Visual Basic、Node.js、HTML、JavaScript等各大编程语言…

KK集团高管变更:陈世欣任总经理,涉无证放贷遭关注,还曾被处罚

近日&#xff0c;KK集团关联公司广东快客电子商务有限公司&#xff08;下称“KK集团”&#xff09;发生工商变更&#xff0c;其中郭惠波不再担任该公司总经理一职&#xff0c;由陈世欣接任。而在早前&#xff0c;陈世欣曾于2020年取代吴悦宁担任总经理职务&#xff0c;2021年7月…

用Python和Scrapy来构建强大的网络爬虫

前言 构建强大的网络爬虫是一个复杂而有挑战性的任务。Python和Scrapy是两个强大的工具&#xff0c;可以帮助我们完成这个任务。在本文中&#xff0c;我将向您展示如何使用Python和Scrapy构建一个强大的网络爬虫&#xff0c;并且还将介绍如何使用代理IP来更好地爬取目标网站。…

上帝视角俯视工厂设计模式

引言 本篇聊聊设计模式中的简单工厂、工厂方法、抽象工厂设计模式&#xff0c;争取在看完这篇后不会再傻傻分不清以及能够应用在实际项目中 背景 以一个咱们都熟悉的场景举个例子&#xff0c;我们平时都会戴口罩&#xff0c;用来过滤一些普通病毒&#xff0c;大致的设计如下…

操作系统期末复习知识点

目录 一.概论 1.操作系统的介绍 2.特性 3.主要功能 4.作用 二.进程的描述与控制 1.进程的定义 2.特性 3.进程的创建步骤 4.基本状态转化 5.PCB的作用 6.进程与线程的比较 三.进程同步 1.同步的概念&#xff08;挺重要的&#xff09; 2.临界区 3.管程和进程的区…

AI日报:大型律师事务所首次推出人工智能工具撰写合同

欢迎订阅专栏 《AI日报》 获取人工智能邻域最新资讯 总览 英国的Allen&Overy推出了一款可以为律师撰写合同的人工智能工具&#xff0c;名为ContractMatrix。 它利用现有的合同模板起草新的合同&#xff0c;律师可以接受或修改。 1000多名律师正在使用该工具。今年1月&…

LeetCode(39)组合总和⭐⭐

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。如…

史上最牛逼的fiddler抓包操作,【工具】Fiddler使用教程

eb调试工具之一&#xff0c; 它能记录所有客户端和服务器的http和https请求。允许你监视、设置断点、甚至修改输入输出数据。Fiddler包含了一个强大的基于事件脚本的子系统&#xff0c;并且能使用.net语言进行扩展。换言之&#xff0c;你对HTTP 协议越了解&#xff0c;你就能越…

033 - STM32学习笔记 - TIM定时器(一) - 高级定时器

033 - STM32学习笔记 - TIM定时器&#xff08;一&#xff09; - 高级定时器 上节内容学习了基本定时器&#xff0c;其功能比较简单&#xff0c;配置和使用也比较容易&#xff0c;今天在基本定时器的基础上学习一下高级控制定时器的内容。 在F429上一共有两个高级控制定时器和1…

给新手的25个建议

前言 最近知乎上&#xff0c;有一位大佬邀请我回答下面这个问题&#xff0c;看到这个问题我百感交集&#xff0c;感触颇多。 在我是新人时&#xff0c;如果有前辈能够指导方向一下&#xff0c;分享一些踩坑经历&#xff0c;或许会让我少走很多弯路&#xff0c;节省更多的学习的…

每日一道算法题day-three(备战蓝桥杯)

哈喽大家好&#xff0c;今天来给大家带来每日一道算法题系列第三天&#xff0c;让我们来看看今天的题目&#xff0c;一起备战蓝桥杯 题目&#xff1a; 小 Y的桌子上放着 n 个苹果从左到右排成一列&#xff0c;编号为从 11 到 n。 小苞是小 Y 的好朋友&#xff0c;每天她都会…

设计模式篇---命令模式(结合spring+动态代理实现开闭)

文章目录 概念结构实例总结 概念 命令模式&#xff1a;将一个请求封装为一个对象&#xff0c;从而可用不同的请求对客户进行参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;以及支持可撤销的操作。 现实生活中&#xff0c;我们用开关来控制一些电器的打开和关闭&am…

NLP电影情绪分析项目

https://machinelearningmastery.com/develop-word-embedding-model-predicting-movie-review-sentiment/ https://machinelearningmastery.com/prepare-movie-review-data-sentiment-analysis/ 本教程分为 5 个部分;他们是&#xff1a; 电影评论数据集数据准备训练嵌入层训练…

解决报错Exception encountered during context initialization

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读报错解决 报错 今天在测试一个类时&#xff0c;突然间报了以下错误。 juni…

调用第三方接口遇到的13大坑

前言 在实际工作中&#xff0c;我们经常需要在项目中调用第三方API接口&#xff0c;获取数据&#xff0c;或者上报数据&#xff0c;进行数据交换和通信。 那么&#xff0c;调用第三方API接口会遇到哪些问题&#xff1f;如何解决这些问题呢&#xff1f; 这篇文章就跟大家一起聊…

详解bookkeeper AutoRecovery机制

引言小故事 张三在一家小型互联网公司上班&#xff0c;由于公司实行的996&#xff0c;因此经常有同事“不辞而别”&#xff0c;为了工作的正常推进&#xff0c;团队内达成了某种默契&#xff0c;这种默契就是通过某个规则来选出一个同事&#xff0c;这个同事除了工作之余还有额…

大数据毕业设计:python房源数据爬虫分析预测系统+可视化 +商品房数据(源码+讲解视频)✅

毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&#xff0c;点赞、关注不迷路&#xff0c;大家在毕设选题&#xff…

【算法】链表每k个节点反转 (js)

牛客链接&#xff1a;https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e?tpId196&&tqId37080&rp1&ru/ta/job-code-total&qru/ta/job-code-total/question-ranking 本人题解&#xff1a; 有点绕&#xff0c;好好理解 /** function Li…

Layui弹窗带标签可切换图表的应用Demo

提供Layui弹窗带页签的Demo写法 文章目录 前言一、展示效果二、详细代码1.代码2.简单释义 总结 前言 之前因为有需求&#xff0c;需要开发Layui的弹出框&#xff0c;同时弹窗框需要支持&#xff0c;页签点击切换内容&#xff0c;特此整理了这一篇文章&#xff0c;提供给需要的…

D-Link DES-108 交换机

D-Link DES-108 交换机 1. 百兆交换机 8 口References ​ D-Link Corporation is a Taiwanese multinational networking equipment manufacturing corporation headquartered in Taipei, Taiwan. Taiwanese&#xff1a;adj. 台湾的 n. 台湾人 headquarter [hedkwɔ:tə]&#…