“笨办法”学Python 3 ——练习 44 继承和组合
练习44 继承和组合
永远记住这一点:继承的大多数用法都可以用组合(composition)来简化或替换。并且无论如何都要避免多重继承。
内容提要:
1. 什么是继承?
(1)隐式继承
(2)显示继承
(3)改变前后
(4)三种组合
(5)为何用super()
(6)组合
2. 何时使用继承和组合
什么是继承?
继承用来表明一个类将从其父类那里获得大多数或所有特性。当你在做这种专门化时,有三种父类和子类可以交互的方法:
(1)对子类的行为意味着对父类的行为。——隐式继承
(2)子类上的操作会覆盖父类上的操作。——显示继承
(3)子类上的操作会更改父类上的操作。
1、隐式继承
代码:ex44a.py
class Parent(object): #创建父类def implicit(self): #创建函数print("PARENT implicit()")class Child(Parent): #创建子类Child,继承至父类Parentpassdad = Parent() #Parent()类实例化
son = Child() #Child()类实例化dad.implicit() #调用父类内部函数
son.implicit() #调用函数继承至父类
输出结果:
PARENT implicit()
PARENT implicit()
说明:
pass关键词:“暂时跳过”,pass 是一种空操作,解释器执行到它的时候,除了检查语法是否合法,什么也不做就直接跳过。使用在函数、类、循环体或者条件判断语句中。用于补充语法的完整性,要不然代码会报错。
Child()的类底下使用pass空块,没有定义实际内容,但它仍旧可以可以调用函数implicit(),就是因为它继承了父类Parent()的函数,这就是隐式继承。因此如果将函数放在父类中(比如 Parent),然后所有子类(比如 Child)会自动获得这些特性。对于需要写很多重复代码的类来说非常方便。
2、显式继承
代码:ex44b.py
#显式继承——子类中定义一个与父类同名的函数,以替换父类中的函数功能
class Parent(): #创建父类def override(self): #创建父类的函数print("Parent override()")class Child(Parent): #创建子类Child继承至父类Parentdef override(self): #创建与父类中函数同名的函数,但功能与其不同print("Child override()")dad = Parent() #实例化父类
son = Child() #实例化子类dad.override() #调用父类中的函数override()
son.override() #调用子类中的函数override()
输出结果:
Parent override()
Child override()
说明:
隐式调用函数的问题在于,有时希望子类与父类的行为有所不同。**只需要在子类( Child) 中定义一个与父类(Parent)同名函数,子类上的操作会覆盖父类上的操作。**如上代码中,父类与子类都同时存在的override()函数,运行之后的结果不同。
3、修改前后
代码:ex44c.py
#子类上的操作会更改父类上的操作
#修改类中函数前后
class Parent(): #创建父类def altered(self): #创建父类函数print("Parent altered()")class Child(Parent): #创建子类def altered(self): #创建与父类函数同名的子类函数,覆盖父类函数print("Child, Before Parent altered()") #打印super().altered() #利用super(超类)调用父类中的函数print("Child, After Parent altered()") #继续打印dad = Parent() #实例化父类
son = Child() #实例化子类dad.altered() #调用父类函数
son.altered() #调用子类函数
输出结果:
Parent altered()
Child, Before Parent altered()
Parent altered()
Child, After Parent altered()
说明:
第三种使用继承的方式是覆盖的一种特殊情况,可以在父类版本运行前后更改子类的函数内容。首先,与之前一样在子类中创建一个与父类同名的函数,覆盖原先的函数;其次使用super()函数调用父类中的函数。
4、以上三中继承形式结合
过一遍这段代码的每一行,并每一行加上注释,说明它的作用。
#三者结合
class Parent(): #创建父类def override(self): #创建父类函数overrideprint("Parent override()") #函数的行为,打印字符串def implicit(self): #创建父类函数implicit()print("Parent implicit()") #函数的行为,打印字符串def altered(self): #创建父类函数altered()print("Parent altered()") #函数的行为,打印字符串class Child(Parent): #创建子类def override(self): #创建与父类中override同名的函数,覆盖父类中该函数的内容print("Child override()")def altered(self): #创建与父类中altered同名函数,覆盖父类该函数内容print("Child, Before Parent altered()")super().altered() #调用函数super(超类),再次继承父类中的函数altered()print("Child, After Parent altered()")dad = Parent() #父类实例化
son = Child() #子类实例化dad.implicit() #调用父类函数implicit()
son.implicit() #子类中未定义函数implicit(),但隐式继承了父类,也可调用该函数,且内容相同dad.override() #调用父类override()函数
son.override() #调用子类override()函数dad.altered() #调用父类altered()函数
son.altered() #调用子类altered()函数
输出结果:
Parent implicit()
Parent implicit()
Parent override()
Child override()
Parent altered()
Child, Before Parent altered()
Parent altered()
Child, After Parent altered()
5、用super()的理由
什么是多重继承?(之前练习有学习了解)
如下代码:
class SuperFun(Child, BadStuff):
pass
如上代码中创建的类SuperFun(),同时继承自Child()和BadStuff()两个类,即一个类继承了一个或多个类就是“多重继承”。
在出现多重继承的情况下,对任何 SuperFun 的实例执行隐式操作时,Python 都必须在 Child 类和 BadStuff 类的层级结构中查找可能的函数,不过它需要以一致的顺序来执行这项操作。为了做到这一点,Python 使用了“方法解析顺序”(method resolution order,MRO)和一种被称为 C3 的算法,这种算法很复杂,因此使用super()函数可以帮助我们在需要修改的地方进行处理即可。
用__init__来使用super()
super() 最常用的用法其实是在子类中使用基类的 init 函数。这通常是你在一个子类中唯一需要做一些操作,然后在父类中完成初始化的地方。
示例如下:
class Child(Parent):def __init__(self, stuff): #初始化函数self.stuff = stuffsuper(Child,self).__init__() #调用父类的初始化函数
6、组合
继承很有用,但是还有一种能实现相同效果的方法,就是使用其他类和模块,而不是依赖于隐式继承。当使用继承时,子类中存在大量的编写新代码来替换或者更改函数功能的时候,可以通过调用模块中的函数来实现。示例如下:
代码ex44e.py
class Other(): #创建一个额外的类Other()def override(self): #创建函数print("Other override()")def implicit(self): #创建类的函数print("Other implicit()")def altered(self): #创建类的函数print("Other altered()")class Child(): #创建类Child()# def __init__(self): #创建初始化函数#创建Other()类与Child()之间的桥梁,也可以没有,但是调用Other()类中的函数方式会有所不用# self.other = Other() def implicit(self): #创建函数implicit()# self.other.implicit() #对应第一种,调用Other()类中的implicit()函数Other().implicit() #对应第二种,调用Other()类中的implicit()函数def override(self): #创建函数override()print("Child override()")def altered(self): #创建altered()函数print("Child, Before Other altered()")# self.other.altered() #第一种,调用Other()类中的altered()函数Other().altered() #第二种,调用Other()类中的函数altered()print("Child, After Other altered()")son = Child() #实例化Child类son.implicit() #调用函数implicit()
son.override() #调用函数override()
son.altered() #调用函数altered()
输出结果:
Other implicit()
Child override()
Child, Before Other altered()
Other altered()
Child, After Other altered()
说明:
可以看到,Child 和 Other 中的大多数代码都是相同的,可以完成相同的事情。唯一的区别是必须定义一个 Child.implicit 函数来完成这个动作。
其中在Child()类中调用Other()类的方法有两种。
第一种,在Child类的__init__函数中定义other属性,self.other = Other(),后续可直接使用self.other.函数名来调用Other类中的函数。
第二种,直接在Child类中,实例化Other类后调用,例如:Other().implicit()
问题:是否可以将Other类放入Other.py的模块中,去调用它?
可以,代码如下:
文件:other.py
class Other(): #创建一个额外的类Other()def override(self): #创建函数print("Other override()")def implicit(self): #创建类的函数print("Other implicit()")def altered(self): #创建类的函数print("Other altered()")
文件:ex44_Child.py
from other import Other #从模块Other中调用Other类class Child(): #创建类Child()def __init__(self): #创建初始化函数#创建Other()类与Child()之间的桥梁,也可以没有,但是调用Other()类中的函数方式会有所不用self.other = Other() def implicit(self): #创建函数implicit()self.other.implicit() #对应第一种,调用Other()类中的implicit()函数# Other().implicit() #对应第二种,调用Other()类中的implicit()函数def override(self): #创建函数override()print("Child override()")def altered(self): #创建altered()函数print("Child, Before Other altered()")self.other.altered() #第一种,调用Other()类中的altered()函数# Other().altered() #第二种,调用Other()类中的函数altered()print("Child, After Other altered()")son = Child() #实例化Child类son.implicit() #调用函数implicit()
son.override() #调用函数override()
son.altered() #调用函数altered()
输出结果:
Other implicit()
Child override()
Child, Before Other altered()
Other altered()
Child, After Other altered()
说明:
可以通过other.py文件调用Other类,只需要在ex44_Child.py 文件的脚本代码中加入import调用模块,即from other import Other。在Child类中的调用方式与之前完全相同。
7、何时使用继承和组合
“继承与组合”的问题可以归结为试图解决可复用代码的问题。
——继承通过在父类中创建隐含相同功能的函数的机制来解决这个问题。
——组合通过提供模块以及调用其他类中的函数来解决这个问题。
三个指导方针(建议,但可能无法遵守):
1、无论如何都要避免多重继承,因为它太复杂而且不可靠。
2、使用组合将代码打包到模块中,这些模块可以用于许多不同的、不相关的地方和情境。
3、代码的可复用部分之间有清楚的关联(很明显的父类与子类关系,如动物和猫)或者必须要用继承时,用继承。
附加练习
阅读 : http://www.python.org/dev/peps/pep-0008/ 文件(该网站需要翻墙)。
相关文章:
“笨办法”学Python 3 ——练习 44 继承和组合
练习44 继承和组合 永远记住这一点:继承的大多数用法都可以用组合(composition)来简化或替换。并且无论如何都要避免多重继承。 内容提要: 1. 什么是继承? (1)隐式继承 (2&#x…...
绕过安全狗拦截的SQL注入
目录 靶场环境及中间件 知识补充 判断存在注入 整形get类注入 字符型GET注入...
JAVA练习62-无重复字符的最长子串、最长回文子串
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目1-无重复字符的最长子串 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 二、题目2-最长回文子串 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总…...
【JavaWeb】复习重点内容
✅✅作者主页:🔗孙不坚1208的博客 🔥🔥精选专栏:🔗JavaWeb从入门到精通(持续更新中) 📋📋 本文摘要:本篇文章主要分享JavaWeb的学习重点内容。 &a…...
基于粒子群改进的灰色神经网络的时间序列预测,PSO-GNN模型,神经网络案例之20
目标 灰色模型原理 神经网络原理 灰色神经网络原理 粒子群算法的原理 粒子群改进灰色神经网络原理 粒子群改进灰色神经网络的代码实现 效果图 结果分析 展望 灰色模型 基本思想是用原始数据组成原始序列(0),经累加生成法生成序列(1),它可以弱化原始数据的随机性,使其呈现…...
Java中的反射使用
1、获取Class对象的三种方式 1、对象调用Object类的getClass()方法(对象.getClass()) 2、调用类的class属性(类名.class) 3、调用Class类的静态方法(Class.forName(“包名.类名”))常用 Student类 package…...
urho3d工具
AssetImporter 加载开放资源导入库支持的各种三维格式(http://assimp.sourceforge.net/)并保存Urho3D模型、动画、材质和场景文件。有关支持的格式列表,请参阅http://assimp.sourceforge.net/main_features_formats.html. Blender的另一种导出路径是使用Urho3D插件…...
HashMap数据结构
HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射。此类不保证映 射的顺序,假定哈希函数将元素适当的分布在各桶之间,可为基本操作(get和put)提供稳定的性能。 HashMap在JDK1.8以前数据结构和存…...
BFC的含义以及应用
什么是BFC? BFC全称是Block Formatting context,翻译过来就是块级格式化上下文。简单来说,BFC是一个完全独立的空间。让空间里的子元素不会影响到外面的布局。😃😃😃 如何触发BFC呢? mdn给了如下方式&a…...
电脑技巧:分享8个Win11系统必备小技巧
目录 1、让任务栏显示“右键菜单” 2、任务栏置顶 3、还原经典右键菜单 4、Win11版任务管理器 5、新版AltTab 6、开始菜单不再卡 7、为Edge浏览器添加云母效果 8、自动切换日/夜模式 Win11在很多地方都做了调整,但由于涉及到诸多旧有习惯,再加上…...
C/C++每日一练(20230226)
目录 17. 电话号码的字母组合 37. 解数独 51. N 皇后 52. N皇后 II 89. 格雷编码 90. 子集 II 17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电…...
Vue 3第二章:Vite文件目录结构及SFC语法
文章目录1. Vite 文件目录结构2. Vue3 SFC 语法规范介绍1. Vite 文件目录结构 Vue3 并没有强制规定文件目录结构,开发者可以按照自己喜欢的方式组织代码。不过,通常情况下,我们会按照以下方式组织文件目录: ├── public │ …...
Leetcode 剑指 Offer II 016. 不含重复字符的最长子字符串
题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个字符串 s ,请你找出其中不含有重复字符的最长…...
TCP 的演化史-sack 与 reordering metric
就着 TCP 本身说事,而不是高谈阔论关于它是如何不合时宜,然后摆出一个更务虚的更新。 从一个 case 开始。 按照现在 Linux TCP(遵守 RFC) 实现,以下是一个将会导致 reordering 更新的 sack 序列: 考虑一种情况,这两个…...
【Spring6】| Spring的入门程序、集成Log4j2日志框架
目录 一:Spring的入门程序 1. Spring的下载 2. Spring的jar文件 3. 第一个Spring程序 4. 第一个Spring程序详细剖析 5. Spring6启用Log4j2日志框架 一:Spring的入门程序 1. Spring的下载 官网地址:https://spring.io/ 官网地址&…...
包子凑数(完全背包)
小明几乎每天早晨都会在一家包子铺吃早餐。 他发现这家包子铺有 N 种蒸笼,其中第 i种蒸笼恰好能放 Ai 个包子。 每种蒸笼都有非常多笼,可以认为是无限笼。 每当有顾客想买 X 个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若…...
Spring超级全家桶,学完绝对是惊艳面试官的程度
前言Spring框架自2002年诞生以来一直备受开发者青睐,它包括SpringMVC、SpringBoot、Spring Cloud、Spring Cloud Dataflow等解决方案。有人亲切的称之为:Spring 全家桶。很多研发人员把spring看作心目中最好的java项目,没有之一。所以这是重点…...
Redis主要数据类型
Redis 是一个数据结构服务器。 Redis 的核心是提供一系列本机数据类型,可帮助您解决从缓存到队列再到事件处理的各种问题Redis主要数据类型:String(字符串),Lists(列表),Sets&#x…...
【Linux | ELK 8.2】搭建ELKB集群Ⅰ—— 实验环境说明和搭建Elasticsearch集群
目录1. 实验环境1.1 实验工具1.2 操作系统1.3 架构版本、IP地址规划与虚拟机配置要求1.4 拓扑图1.5 其他要求2. 实验步骤2.1 安装Elasticsearch(单节点)(1)检查系统jdk版本(2)下载elasticsearch(…...
不同情况下*p和*p的区别(指针)
一说到指针,不少同学就会觉得云里雾里。首先要明白,指针和地址是一个概念;然后明白指针和指针变量的区别。先理解地址和数据,想象内存里面是一个个的小盒子,每个盒子对应一个编号,这个编号就是地址…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
