当前位置: 首页 > 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…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...