首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第 13章 性能测量和大O算法分析
13.1 timeit模块
13.2 cProfile分析器
13.3 大O算法分析
13.4 大O阶
13.4.1 使用书架打比方描述大O阶
13.4.2 大O 测量的是最坏情况
13.5 确定代码的大O 阶
13.5.1 为什么低阶项和系数不重要
13.5.2 大O 分析实例
13.5.3 常见函数调用的大O 阶
13.5.4 一眼看出大O 阶
13.5.5 当n 很小时,大O并不重要,而n通常都很小
第 14章 项目实战
14.1 汉诺塔
14.1.1 汉诺塔输出
14.1.2 汉诺塔源代码
14.1.3 汉诺塔编写代码
14.2 四子棋
14.2.1 四子棋输出
14.2.2 四子棋源代码
14.2.3 四子棋编写代码
第 15章 面向对象编程和类
15.1 拿现实世界打比方:填写表格
15.2 基于类创建对象
15.3 创建一个简单的类——WizCoin
15.3.1 方法__init__()和self
15.3.2 特性
15.3.3 私有特性和私有方法
15.4 函数type()和特性__qualname__
15.5 非OOP 和OOP 的例子:井字棋
15.6 为现实世界设计类是一件难事儿
第 16章 面向对象编程和继承
16.1 继承的原理
16.1.1 重写方法
16.1.2 super()函数
16.1.3 倾向于组合而非继承
16.1.4 继承的缺点
16.2 函数isinstance()和issubclass()
16.3 类方法
16.4 类特性
16.5 静态方法
16.6 何时应该使用类和静态的面向对象特性
16.7 面向对象的行话
16.7.1 封装
16.7.2 多态性
16.8 何时不应该使用继承
16.9 多重继承
16.10 方法解析顺序
第 17章 Python 风格的面向对象编程:属性和魔术方法
17.1 属性
17.1.1 将特性转换为属性
17.1.2 使用setter 验证数据
17.1.3 只读属性
17.1.4 什么时候应该使用属性
17.2 Python 的魔术方法
17.2.1 字符串表示魔术方法
17.2.2 数值魔术方法
17.2.3 反射数值魔术方法
17.2.4 原地魔术方法
17.2.5 比较魔术方法
当前位置:
首页>>
技术小册>>
Python编程轻松进阶(五)
小册名称:Python编程轻松进阶(五)
### 16.8 何时不应该使用继承 在Python编程的广阔天地中,继承作为一种强大的代码复用和扩展机制,被广泛应用于构建复杂的软件系统和框架。然而,正如任何强大的工具都有其适用边界一样,继承也并非解决所有问题的万能钥匙。在某些情况下,滥用继承反而会导致代码结构混乱、维护困难、扩展性受限等问题。因此,理解何时应该避免使用继承,是每一位Python开发者进阶路上的重要一课。 #### 1. 过度使用继承导致的“脆弱基类”问题 当一个类被设计为基类(Base Class),并预期将被多个子类(Subclass)继承时,基类中的任何修改都可能影响到所有子类。这种紧耦合关系使得基类成为系统中的“脆弱点”。如果基类的方法或属性发生变化,开发者需要仔细评估这些变化对所有子类的影响,这既耗时又容易出错。特别是当基类的改动是出于修复bug或性能优化时,这些改动可能并非所有子类都需要的,从而增加了不必要的复杂性。 **解决方案**: - **组合(Composition)优于继承**:在可能的情况下,使用组合来代替继承。组合允许对象持有其他对象的引用,从而可以在运行时动态地组合功能,避免了继承带来的静态绑定和紧耦合问题。 - **接口隔离**:如果必须使用继承,尽量保持基类的简单和稳定,通过定义清晰的接口来隔离变化,减少基类对子类的直接影响。 #### 2. 继承链过长导致的“深度继承”问题 随着项目的发展,继承层次可能会变得越来越深,形成所谓的“深度继承”或“多重继承”的复杂结构。这种结构不仅难以理解,还可能导致“钻石问题”(在多重继承中,如果两个基类共同继承自第三个基类,并且都重写了该基类中的某个方法,那么子类在调用该方法时就会产生歧义)等难以预料的错误。 **解决方案**: - **简化继承结构**:重新评估和设计类的继承关系,尽可能简化继承链,减少不必要的继承层级。 - **使用混合类(Mixin)**:对于需要在多个类之间共享的功能,可以使用混合类(Mixin)来实现。混合类是一种特殊的类,它只包含属性和方法,不设计实例化。通过组合混合类,可以灵活地组合多个功能,而无需创建复杂的继承结构。 #### 3. 继承用于代码复用而非表达“是一种”关系 继承的初衷是表达一种“是一种”(is-a)的关系,即子类是基类的一个特殊类型。然而,在实际开发中,有时开发者会错误地将继承用于代码复用,即使子类与基类之间并不满足“是一种”的关系。这种用法会破坏类的自然语义,使得代码难以理解和维护。 **解决方案**: - **明确继承的语义**:在决定使用继承之前,首先明确子类与基类之间是否存在“是一种”的关系。如果不存在,考虑使用组合或其他设计模式来实现代码复用。 - **利用函数和模块**:对于可以在多个类中复用的功能,考虑将其封装为独立的函数或模块,通过导入和使用这些函数或模块来实现代码复用。 #### 4. 继承用于实现多态而非类型约束 多态是面向对象编程中的一个重要特性,它允许不同类的对象对同一消息作出响应。然而,有时开发者会错误地使用继承来实现多态,通过定义复杂的继承层次来约束对象的类型。这种做法限制了代码的灵活性和可扩展性。 **解决方案**: - **利用抽象基类(ABC)**:在Python中,可以使用`abc`模块定义抽象基类,并在其中声明抽象方法。子类必须实现这些抽象方法才能被实例化。这种方式既保留了多态性,又通过接口约束了子类的行为,而不必依赖于复杂的继承结构。 - **使用类型注解和协议**:从Python 3.5开始,类型注解(Type Hints)被引入以支持静态类型检查。通过类型注解和第三方库(如`mypy`)提供的协议(Protocols),可以在不依赖继承的情况下定义接口约束,实现更加灵活和强大的类型系统。 #### 5. 继承导致的“模板方法”滥用 模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并允许子类为一个或多个步骤提供具体实现。然而,在某些情况下,开发者可能会过度依赖模板方法模式,通过继承来定义过多的模板步骤,导致基类变得庞大而复杂。 **解决方案**: - **策略模式**:考虑使用策略模式来替代模板方法模式。策略模式允许在运行时选择算法的具体实现,通过组合不同的策略对象来灵活组合算法步骤,而无需通过继承来定义固定的算法骨架。 - **简化基类**:重新审视基类的设计,确保它只包含必要的框架和接口,而将具体的实现细节留给子类或其他组件。 #### 结语 继承是面向对象编程中的一个核心概念,它为我们提供了强大的代码复用和扩展能力。然而,正如任何强大的工具一样,继承也需要在合适的场景下使用才能发挥其最大的效用。在决定使用继承之前,我们需要仔细评估其带来的好处和潜在的风险,并考虑是否有更合适的替代方案。通过理解何时应该避免使用继承,我们可以编写出更加清晰、灵活和可维护的代码,为Python编程的进阶之路打下坚实的基础。
上一篇:
16.7.2 多态性
下一篇:
16.9 多重继承
该分类下的相关小册推荐:
Python合辑4-130个字符串操作示例
Python合辑14-面向对象编程案例(下)
Python爬虫入门与实战开发(上)
Python3网络爬虫开发实战(上)
Python高性能编程与实战
Python合辑7-集合、列表与元组
Python神经网络入门与实践
Python面试指南
Python编程轻松进阶(四)
Python编程轻松进阶(一)
Python合辑9-判断和循环
Python编程轻松进阶(三)