Python学习笔记12:进阶篇(二),类的继承与组合

2024-06-19 01:52

本文主要是介绍Python学习笔记12:进阶篇(二),类的继承与组合,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

类的继承

我们在编写一系列的类的时候,会发现这些类很相似,但是又有各自的特点和行为。在编写这些类的时候,我们可以把相同的部分抽象成一个基类,然后根据其他不同的特点和行为,抽象出子类,继承这个基类。通过继承,我们就可以方便的完整这一些列类的抽象。

示例

class Person:def __init__(self, name, age):self.name = nameself.age = ageself.country = "中国"  # 设置默认值def speak(self):print(f"大家好, 我的名字是{self.name}, 今年{self.age}岁,我来自{self.country}. 我讲的是普通话.")class GuangdongPerson(Person):def __init__(self, name, age):super().__init__(name, age)self.province = "广东"def speak(self):print(f"大家好, 我是{self.name}, 今年{self.age}岁,我来自{self.country}{self.province}. 我会讲广东话.")class TaiwanPerson(Person):def __init__(self, name, age):super().__init__(name, age)self.province = "台湾"def speak(self):print(f"大家好, 我是{self.name}, 今年{self.age}岁,我来自{self.country}{self.province}. 我会讲台湾话.")zhang_san = GuangdongPerson("张三", 18)
li_si = TaiwanPerson("李四", 20)
zhang_san.speak()
li_si.speak()

在这里插入图片描述

例子不能说讲的很好哈,能理解就行。像我之前推荐的书,书里的举例是car,其他教程里面可能还有shape。但是举什么例子不重要,重要的是了解什么是继承,继承能干什么,有什么意义,好处和坏处是什么。

什么是继承

继承是一种面向对象编程的基本特性,它允许我们定义一个类(称为子类或派生类),该类可以从另一个已经存在的类(称为父类或基类)那里继承属性和方法。这意味着子类会自动获得父类的所有功能,同时还可以定义或修改自己的属性和方法,或者覆盖父类的方法来实现特定的功能。
在示例中,我们先定义了一个父类Person。而后定义了GuangdongPerson和TaiwanPerson两个类,这两个类定义了自己的属性,继承Person类的三个属性和函数,最后我们重写来自于父类的方法。

为什么要继承

继承的主要目的是促进代码的复用性、模块化和易于维护。通过继承,我们可以创建一个通用的基类来封装共同的行为,然后为具有特殊需求的子类添加或修改功能,而不需要重复编写相同的代码。

继承有哪些缺点

没有完美无缺的事物,继承在提供便利的同时也带来一些问题:

  1. 过度耦合: 如果子类过于依赖父类的实现细节,当父类发生变化时,可能会对子类产生意想不到的影响。这种紧密的耦合关系使得代码难以修改和维护。
  2. 复杂度增加: 随着继承层次的加深,类结构会变得更加复杂。开发者需要跟踪多个层级的继承关系,理解每个类的功能和责任变得困难。
  3. 灵活性降低: 继承是静态的,一旦一个类继承了另一个类,这种关系就固定下来,不能在运行时改变。这限制了代码的灵活性和可重用性。
  4. 菱形问题(Diamond Problem): 在多继承的语言中,如果多个父类拥有同一个方法或属性,子类可能会遇到冲突,不确定应该使用哪一个父类的实现。
  5. 代码可读性和可维护性下降: 过度使用继承可能导致“类爆炸”,即类的数量急剧增加,这会使代码库变得庞大且难以管理。

什么时候用继承

选择使用继承主要取决于以下几个场景和原则:

  1. 共享行为和属性: 当多个类具有相似的属性和行为时,可以考虑使用继承。一个基类可以定义这些共性部分,而子类则专注于差异化的部分。例如,各种动物类可能都共享“移动”和“吃”的行为,但具体实现各不相同。
  2. 代码复用: 继承允许子类重用父类的代码,减少重复代码,提高代码的可维护性。如果多个类需要执行相同的操作或拥有相同的属性,通过继承可以避免重复定义这些内容。
  3. 层次结构: 当类之间存在明显的层次或分类关系时,继承是自然的选择。例如,在一个图形界面库中,Widget类可以作为基类,而Button、TextBox等具体控件类继承自它,形成一个清晰的层次结构。
  4. 接口一致性: 如果希望一组类提供一致的接口给外部使用者,即使它们的内部实现不同,也可以通过继承来实现。这使得客户端代码可以以统一的方式处理这些类的实例。
  5. 抽象类和接口: 使用抽象基类(ABC)可以定义一个接口或模板,强制子类必须实现特定的方法,从而保证了设计的一致性和约束性。

通常继承和组合两个方式来实现某些属性和行为的复用。当两个类之间的关系不是“is-a”的关系,而是“has-a”的关系时,组合(包含另一个类的实例)通常是更好的选择。

组合

当我们需要复用某些类的属性和行为的时候,使用继承的方式和客观事实相违背,但是有另一个符合客观事实的复用方式,就是组合。简单理解为定义一个类A的时候,将另一个已存在的类BA自己本身的一些属性和行为放到一起组合成类A

什么是组合

组合(Composition)是面向对象编程中的另一种重要的设计原则,用于表示“整体-部分”(has-a)的关系,而不是继承所表达的“是一个”(is-a)的关系。在组合中,一个类的对象可以包含另一个或多个类的对象作为其属性,以此来实现更复杂的功能或结构,而无需通过继承来扩展类的功能。

组合的好处

  1. 灵活性:相比于继承,组合提供了更高的灵活性。因为对象可以在运行时动态地添加、替换或移除其组成部分,这使得系统更加灵活,更容易适应变化。
  2. 明确的责任分配:每个对象负责自身的功能,整体对象通过协调其组成部分来完成更复杂的任务,这有助于遵循单一职责原则。
  3. 避免继承的局限性:组合可以有效避免继承的缺点,如多重继承的菱形问题、过深的继承层次导致的复杂性等。
  4. 促进代码重用:通过将复杂对象构建为简单对象的组合,可以在不同的上下文中重用这些简单对象,而不需要创建新的继承层次。

什么时候用组合

  1. 当一个类需要使用另一个类的功能,但两者之间不存在“是一种”关系时。
  2. 当需要在运行时动态地调整或扩展对象的功能时。
  3. 当想要设计出高度可配置和可变的对象结构时。

示例

class Engine:def start(self):print("Engine started.")class ElectricEngine(Engine):def start(self):print("Electric Engine started.")class InternalCombustionEngine(Engine):def start(self):print("Internal Combustion Engine started.")class Car:def __init__(self):self.engine = Engine()  # Car类包含了一个Engine对象,这就是组合def set_engine(self, engine):self.engine = enginedef start_car(self):self.engine.start()  # 通过组合的Engine对象来启动汽车my_car = Car()
# 普通引擎
my_car.start_car()
my_car.set_engine(ElectricEngine())
# 电动引擎
my_car.start_car()
my_car.set_engine(InternalCombustionEngine())
# 汽油引擎
my_car.start_car()

在这里插入图片描述
在例子中,我们需要定义一个汽车类。汽车可以通过引擎启动。所以我们先定义一个引擎类来启动汽车。这个时候问题来了,汽车继承引擎,是不是很奇怪。汽车和引擎很明显不是is-a的关系,而是has-a的关系,所以我们需要使用组合的方式,将引擎类作为汽车的一个属性封装到汽车类中。
最后,使用不同的引擎,启动方法的实现也不一样,成功完成目标需求。

作业:

  1. 了解is-a和has-a,举出例子,分别使用继承和组合的方式实现类的复用。

下课!!!

点赞收藏关注,感谢支持!!!

这篇关于Python学习笔记12:进阶篇(二),类的继承与组合的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1073677

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学