当前位置: 首页 > news >正文

“笨办法”学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接口实现的&#xff0c;它存储的是内容是键值对<key,value>映射。此类不保证映 射的顺序&#xff0c;假定哈希函数将元素适当的分布在各桶之间&#xff0c;可为基本操作(get和put)提供稳定的性能。 HashMap在JDK1.8以前数据结构和存…...

BFC的含义以及应用

什么是BFC? BFC全称是Block Formatting context&#xff0c;翻译过来就是块级格式化上下文。简单来说&#xff0c;BFC是一个完全独立的空间。让空间里的子元素不会影响到外面的布局。&#x1f603;&#x1f603;&#x1f603; 如何触发BFC呢&#xff1f; mdn给了如下方式&a…...

电脑技巧:分享8个Win11系统必备小技巧

目录 1、让任务栏显示“右键菜单” 2、任务栏置顶 3、还原经典右键菜单 4、Win11版任务管理器 5、新版AltTab 6、开始菜单不再卡 7、为Edge浏览器添加云母效果 8、自动切换日/夜模式 Win11在很多地方都做了调整&#xff0c;但由于涉及到诸多旧有习惯&#xff0c;再加上…...

C/C++每日一练(20230226)

目录 17. 电话号码的字母组合 37. 解数独 51. N 皇后 52. N皇后 II 89. 格雷编码 90. 子集 II 17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电…...

Vue 3第二章:Vite文件目录结构及SFC语法

文章目录1. Vite 文件目录结构2. Vue3 SFC 语法规范介绍1. Vite 文件目录结构 Vue3 并没有强制规定文件目录结构&#xff0c;开发者可以按照自己喜欢的方式组织代码。不过&#xff0c;通常情况下&#xff0c;我们会按照以下方式组织文件目录&#xff1a; ├── public │ …...

Leetcode 剑指 Offer II 016. 不含重复字符的最长子字符串

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长…...

TCP 的演化史-sack 与 reordering metric

就着 TCP 本身说事&#xff0c;而不是高谈阔论关于它是如何不合时宜&#xff0c;然后摆出一个更务虚的更新。 从一个 case 开始。 按照现在 Linux TCP(遵守 RFC) 实现&#xff0c;以下是一个将会导致 reordering 更新的 sack 序列&#xff1a; 考虑一种情况&#xff0c;这两个…...

【Spring6】| Spring的入门程序、集成Log4j2日志框架

目录 一&#xff1a;Spring的入门程序 1. Spring的下载 2. Spring的jar文件 3. 第一个Spring程序 4. 第一个Spring程序详细剖析 5. Spring6启用Log4j2日志框架 一&#xff1a;Spring的入门程序 1. Spring的下载 官网地址&#xff1a;https://spring.io/ 官网地址&…...

包子凑数(完全背包)

小明几乎每天早晨都会在一家包子铺吃早餐。 他发现这家包子铺有 N 种蒸笼&#xff0c;其中第 i种蒸笼恰好能放 Ai 个包子。 每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 X 个包子&#xff0c;卖包子的大叔就会迅速选出若干笼包子来&#xff0c;使得这若…...

Spring超级全家桶,学完绝对是惊艳面试官的程度

前言Spring框架自2002年诞生以来一直备受开发者青睐&#xff0c;它包括SpringMVC、SpringBoot、Spring Cloud、Spring Cloud Dataflow等解决方案。有人亲切的称之为&#xff1a;Spring 全家桶。很多研发人员把spring看作心目中最好的java项目&#xff0c;没有之一。所以这是重点…...

Redis主要数据类型

Redis 是一个数据结构服务器。 Redis 的核心是提供一系列本机数据类型&#xff0c;可帮助您解决从缓存到队列再到事件处理的各种问题Redis主要数据类型&#xff1a;String&#xff08;字符串&#xff09;&#xff0c;Lists&#xff08;列表&#xff09;&#xff0c;Sets&#x…...

【Linux | ELK 8.2】搭建ELKB集群Ⅰ—— 实验环境说明和搭建Elasticsearch集群

目录1. 实验环境1.1 实验工具1.2 操作系统1.3 架构版本、IP地址规划与虚拟机配置要求1.4 拓扑图1.5 其他要求2. 实验步骤2.1 安装Elasticsearch&#xff08;单节点&#xff09;&#xff08;1&#xff09;检查系统jdk版本&#xff08;2&#xff09;下载elasticsearch&#xff08…...

不同情况下*p和*p的区别(指针)

一说到指针&#xff0c;不少同学就会觉得云里雾里。首先要明白&#xff0c;指针和地址是一个概念&#xff1b;然后明白指针和指针变量的区别。先理解地址和数据&#xff0c;想象内存里面是一个个的小盒子&#xff0c;每个盒子对应一个编号&#xff0c;这个编号就是地址&#xf…...

Vuex基础语法

Vuex vuex官网 文章目录Vuexvuex的工作原理图2.vuex的环境搭建3.vuex的使用1.actons2. mutations3.getters4.vuex中的map映射属性4.1 mapState和mapGetters4.2 mapMutations和mapActions5.vuex多组件通信1.通过计算属性获得2.通过mapState获得6.vuex模块化和命名空间6.1模块化…...

刚上岸字节测试开发岗,全网最真实的大厂面试真题

首先我来解释一下为什么说是全网最真实的面试题&#xff0c;相信大家也发现软件测试面试题在网上流传也已不少&#xff0c;但是经过仔细查看发现了两个很重要的问题。 第一&#xff0c;网上流传的面试题的答案并不能保证百分百正确。也就是说各位朋友辛辛苦苦花了很多时间准备…...

Mac监控键盘输入并执行动作

最新内容在我的另一个博客&#xff1a;Mac监控键盘输入并执行动作 背景 电脑的安全是非常重要的&#xff0c;特别是里面的敏感数据&#xff0c;若是被有心之人利用&#xff0c;那后果不堪设想。 所以我们部门定下了一个规矩&#xff0c;谁离开工位要是不锁屏&#xff0c;就可以…...

Transformer输出张量的值全部相同?!

Transformer输出张量的值全部相同&#xff1f;&#xff01;现象原因解决现象 输入经过TransformerEncoderLayer之后&#xff0c;基本所有输出都相同了。 核心代码如下&#xff0c; from torch.nn import TransformerEncoderLayer self.trans TransformerEncoderLayer(d_mode…...

港科夜闻|全国政协副主席梁振英先生率香港媒体高管团到访香港科大(广州)...

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、全国政协副主席梁振英先生率香港媒体高管团到访香港科大(广州)。2月21日下午&#xff0c;在全国政协副主席、广州南沙粤港合作咨询委员会顾问梁振英先生的带领下&#xff0c;香港20余家媒体的高管及知名媒体人士到访香港科大…...

XML调用 CAPL Test Function

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

Linux网络配置(NAT)

在搭配好一台虚拟机的时候想要下载&#xff0c;安装些什么但一直失败这个时候就可以检查一下网络是否连接这里我们使用centos7举例子使用命令——ifconfig由此可见我们的系统中目前有3个网卡ens33——用于接入外网&#xff0c;该网卡默认关闭lo——用于访问本地网络&#xff0c…...

数据结构——第二章 线性表(8)——线性表总结

线性表总结 线性表是线性结构的基本形式&#xff0c;用于描述一组同类型而具有1:1线性关系的数据对象。将此类数据对象存放在计算机的内存中时&#xff0c;必须考虑数据元素的存放和数据元素之间关系的存放。常用的存储结构有顺序存结构和链式结构。 顺序表存储特点是用一维数…...

3.7寸按键翻页工牌

产品参数 产品型号 ESL_BWR3.7_BLE 产品尺寸 (mm) 62.51066.5 显示技术 E ink 显示区域 (mm) 47.32(H)81.12(V) 分辨率 (像素) 280480 像素尺寸(mm) 0.1690.169 150dpi 显示颜色 黑/白 视觉角度 180 工作温度 0℃ - 50℃ 电池 500mAh ( Type-C 充电…...

西北工业大学大学物理(II)选填解析2019-2020期末

2 又是考查“一个电子和一个光子具有相同的波长&#xff0c;则二者动量相等。”4 斯特恩盖拉赫实验&#xff0c;原子的自旋磁矩取向量子化。7 通常我们感受不到电子的波动性。因为其波长短&#xff0c;其实也就是粒子运动速率高。10 考查无限长直导线周围B分布。常见的模型要记…...