Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
01-【Python-Day 1】告别编程恐惧:轻松掌握 Python 安装与第一个程序的 6 个步骤
02-【Python-Day 2】掌握Python基石:变量、内存、标识符及int/float/bool数据类型
03-【Python-Day 3】玩转文本:字符串(String)基础操作详解 (上)
04-【Python-Day 4】玩转文本:Python 字符串常用方法深度解析 (下篇)
05-【Python-Day 5】Python 格式化输出实战:%、format()、f-string 对比与最佳实践
06- 【Python-Day 6】从零精通 Python 运算符(上):算术、赋值与比较运算全解析
07-【Python-Day 7】从零精通 Python 运算符(下):逻辑、成员、身份运算与优先级规则全解析
08-【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析
09-【Python-Day 9】掌握循环利器:for 循环遍历序列与可迭代对象详解
10-【Python-Day 10】Python 循环控制流:while 循环详解与 for 循环对比
11-【Python-Day 11】列表入门:Python 中最灵活的数据容器 (创建、索引、切片)
12-【Python-Day 12】Python列表进阶:玩转添加、删除、排序与列表推导式
13-【Python-Day 13】Python 元组 (Tuple) 详解:从创建、操作到高级应用场景一网打尽
14-【Python-Day 14】玩转Python字典(上篇):从零开始学习创建、访问与操作
15-【Python-Day 15】深入探索 Python 字典 (下):常用方法、遍历、推导式与嵌套实战
16-【Python-Day 16】代码复用基石:详解 Python 函数的定义与调用
17-【Python-Day 17】玩转函数参数(上):轻松掌握位置、关键字和默认值
18-【Python-Day 18】玩转函数参数(下):*args 与 **kwargs 终极指南
19-【Python-Day 19】函数的回响:深入理解 return 语句与返回值
20-【Python-Day 20】揭秘Python变量作用域:LEGB规则与global/nonlocal关键字详解
21-【Python-Day 21】一行搞定!Python lambda 匿名函数的妙用与实战
22-【Python-Day 22】代码的基石:模块(Module)的导入与使用详解
23-【Python-Day 23】Python 模块化编程实战:创建、导入及 sys.path 深度解析
24-【Python-Day 24】告别杂乱代码!一文掌握 Python 包(Package)的创建与使用
25-【Python-Day 25】玩转数字:精通 math 与 random 模块,从数学运算到随机抽样
26-【Python-Day 26】解锁时间魔法:深入解析 time 与 datetime 模块
27-【Python-Day 27】轻松驾驭操作系统:精通 os 与 sys 模块核心功能
28-【Python-Day 28】从指令到蓝图:Python面向对象编程(OOP)入门指南
29-【Python-Day 29】万物皆对象:详解 Python 类的定义、实例化与 __init__ 方法
30-【Python-Day 30】从 self、cls 到 @staticmethod:Python 面向对象三大方法深度解析
31-【Python-Day 31】一文搞懂 Python 实例属性与类属性:从定义、区别到应用场景
32-【Python-Day 32】面向对象基石之封装:从 __private 到 @property 的深度解析
33-【Python-Day 33】OOP核心之继承(Inheritance):代码复用与扩展的艺术
文章目录
摘要
本文是 Python 面向对象编程(OOP)核心概念系列文章的第三篇,将深入探讨“继承”(Inheritance)。继承是面向对象三大特性之一,它允许我们创建一个新类(子类),该类可以获取一个已存在类(父类)的属性和方法,从而实现代码的高度复用和逻辑扩展。本文将从继承的基本概念、语法结构、方法重写(Method Overriding)等多个维度,结合生活中的类比和丰富的代码示例,带您全面掌握 Python 中的继承机制,为构建清晰、可维护的类层次结构打下坚实的基础。
一、继承(Inheritance)的宏观理解
在深入代码之前,我们首先需要建立对“继承”这一概念的宏观认识。为什么需要继承?它在面向对象编程中扮演着怎样的角色?
1.1 生活中的类比:家族的传承
想象一下现实世界中的家族传承。子女会从父母那里继承一些特征,比如姓氏、肤色、相貌等。但同时,子女也会有自己独特的个性和技能。
在编程世界里,继承与此非常相似:
- 父类(Parent Class):就像是父母,它定义了一组通用的属性(特征)和方法(技能)。例如,“动物”类可以有“年龄”、“体重”等属性,以及“吃”、“睡”等方法。
- 子类(Child Class):就像是子女,它继承了父类的所有公共属性和方法,无需重新编写。例如,“狗”类作为“动物”的子类,天生就拥有了“年龄”、“体重”属性,以及“吃”、“睡”的能力。
- 扩展与特化:同时,子类还可以定义自己独有的属性和方法,或者对从父类继承来的方法进行“改造”,以适应自身的特点。比如,“狗”类可以有自己独特的“品种”属性,以及一个与普通动物不同的“叫”(汪汪叫)的方法。
下面用一张图来直观地展示这种关系:
graph TD;
A[<strong>父类:动物 (Animal)</strong><br/>- 属性: name, age<br/>- 方法: eat(), sleep()] --> B[<strong>子类:狗 (Dog)</strong><br/>(继承 Animal)<br/>- 独有属性: breed<br/>- 重写方法: speak() -> '汪汪'];
A --> C[<strong>子类:猫 (Cat)</strong><br/>(继承 Animal)<br/>- 独有属性: color<br/>- 重写方法: speak() -> '喵喵'];
1.2 技术层面的定义
在面向对象编程(OOP)中,继承是一种强大的机制,它允许一个类(称为子类或派生类)获取另一个类(称为父类、基类或超类)的属性和方法。
- 父类 (Parent Class) / 基类 (Base Class): 被继承的类。
- 子类 (Child Class) / 派生类 (Derived Class): 继承自其他类的类。
1.3 继承的核心价值
使用继承主要有两个核心目的:
- 代码复用 (Code Reusability):当多个类具有共同的属性和方法时,可以将这些共同的部分提取出来定义在一个父类中。子类只需继承这个父类,就可以直接使用这些代码,避免了在每个类中重复编写相同的逻辑,大大提高了开发效率和代码的可维护性。
- 构建层次化的类结构 (Hierarchical Class Structure):继承使得类与类之间产生了“is-a”(是一个)的关系(例如,狗“是一个”动物)。这种关系有助于我们更好地组织和理解代码的逻辑结构,使其更贴近现实世界的模型。
二、Python 中单继承的实现
掌握了基本概念后,我们来看看如何在 Python 中用代码实现继承。Python 支持单继承和多重继承,本篇我们首先聚焦于最常见的单继承。
2.1 基本语法结构
在 Python 中实现继承非常简单,只需在定义子类时,在类名后的括号里写上父类的名字即可。
# 定义一个父类
class ParentClass:
# 父类的属性和方法
pass
# 定义一个子类,继承自 ParentClass
class ChildClass(ParentClass):
# 子类可以添加自己的属性和方法,也可以使用父类的
pass
2.2 一个简单的继承示例
让我们通过一个具体的例子来感受继承的魔力。我们将创建一个 Animal 父类和一个继承自它的 Dog 子类。
2.2.1 定义父类 Animal
# 定义父类:动物
class Animal:
def __init__(self, name, age):
"""
Animal 类的构造方法,用于初始化所有动物共有的属性。
"""
print("父类 Animal 的构造方法被调用了!")
self.name = name
self.age = age
def eat(self):
"""
所有动物共有的'吃'方法。
"""
print(f"{self.name} 正在吃东西。")
def sleep(self):
"""
所有动物共有的'睡'方法。
"""
print(f"{self.name} 正在睡觉。")
2.2.2 定义子类 Dog
现在,我们定义一个 Dog 类,让它继承 Animal。注意,Dog 类内部我们暂时不写任何代码。
# 定义子类:狗,它继承自 Animal 类
class Dog(Animal):
# 使用 pass 关键字表示这是一个空的代码块,我们暂时不添加任何新功能
pass
2.2.3 验证继承关系
接下来,我们创建 Dog 类的实例,并尝试调用 Animal 类中定义的方法和访问其属性。
# 实例化子类 Dog
# 注意:虽然 Dog 类是空的,但它继承了 Animal 的 __init__ 方法,
# 所以创建实例时需要传入 name 和 age 参数。
my_dog = Dog("旺财", 2)
# 访问从父类继承来的属性
print(f"我的狗叫 {my_dog.name},它 {my_dog.age} 岁了。")
# 调用从父类继承来的方法
my_dog.eat()
my_dog.sleep()
代码执行结果:
父类 Animal 的构造方法被调用了!
我的狗叫 旺财,它 2 岁了。
旺财 正在吃东西。
旺财 正在睡觉。
结果分析:
从输出中我们可以清晰地看到:
- 当我们创建
Dog的实例my_dog时,父类Animal的__init__方法被自动调用了,并成功初始化了name和age属性。 my_dog对象可以直接访问在Animal中定义的name和age属性。my_dog对象可以成功调用在Animal中定义的eat()和sleep()方法。
这完美地证明了:子类 Dog 完整地继承了父类 Animal 的属性和方法,尽管 Dog 类的定义是空的。 这就是代码复用的直接体现。
三、方法重写(Method Overriding)
子类虽然继承了父类的方法,但有时父类的方法行为并不能完全满足子类的需求。这时,子类就需要对继承来的方法进行“定制化改造”,这个过程就叫做方法重写(或称方法覆盖)。
3.1 为什么需要方法重写?
回到我们的例子,Animal 类可以定义一个通用的 speak() 方法。但是,不同动物的叫声是不同的,狗是“汪汪”叫,猫是“喵喵”叫。如果 Dog 和 Cat 类都直接使用 Animal 的通用 speak() 方法,显然不符合实际情况。
因此,子类需要提供一个属于自己的 speak() 方法版本,来覆盖掉父类的同名方法。
3.2 如何实现方法重写?
在子类中,定义一个与父类中方法名完全相同的方法,即可实现重写。当子类实例调用该方法时,Python 会优先调用子类中定义的版本,而不是父类的版本。
3.3 方法重写的示例
我们来扩展之前的例子,为 Animal 添加一个通用的 speak 方法,然后在 Dog 和 Cat 子类中分别重写它。
# 1. 重新定义父类 Animal,增加一个通用的 speak 方法
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} 正在吃东西。")
def speak(self):
# 这是一个通用的叫声,可能不适用于所有动物
print(f"{self.name} 发出了一些声音...")
# 2. 定义 Dog 子类,并重写 speak 方法
class Dog(Animal):
def speak(self):
# Dog 类对 speak 方法进行了重写,提供了自己的实现
print(f"{self.name} 大声地 '汪!汪!'")
# 3. 定义 Cat 子类,也重写 speak 方法
class Cat(Animal):
def speak(self):
# Cat 类也对 speak 方法进行了重写
print(f"{self.name} 温柔地 '喵~'")
# 4. 创建实例并测试
generic_animal = Animal("某个动物")
my_dog = Dog("大黄")
my_cat = Cat("咪咪")
print("--- 通用动物的行为 ---")
generic_animal.speak()
print("\n--- 狗的行为 ---")
my_dog.eat() # 调用继承自父类的方法
my_dog.speak() # 调用子类重写后的方法
print("\n--- 猫的行为 ---")
my_cat.eat() # 调用继承自父类的方法
my_cat.speak() # 调用子类重写后的方法
代码执行结果:
--- 通用动物的行为 ---
某个动物 发出了一些声音...
--- 狗的行为 ---
大黄 正在吃东西。
大黄 大声地 '汪!汪!'
--- 猫的行为 ---
咪咪 正在吃东西。
咪咪 温柔地 '喵~'
结果分析:
generic_animal对象调用speak()时,执行的是Animal类中的版本。my_dog和my_cat对象虽然都继承自Animal,但当它们调用speak()方法时,执行的分别是各自类中重写后的版本。eat()方法没有被重写,所以my_dog和my_cat调用的仍然是Animal父类中的eat()方法。
这个例子清晰地展示了方法重写的威力:它允许子类在保持与父类接口一致性(都有 speak 方法)的前提下,实现自己独特的行为。
四、实际应用场景
继承不仅仅是理论概念,它在实际软件开发中无处不在。
4.1.1 GUI 开发
在图形用户界面(GUI)开发中,比如使用 Tkinter 或 PyQt 库,我们通常会创建一个自定义的窗口或按钮。这时,我们的自定义类会继承自库提供的基础 Window 或 Button 类,从而获得窗口或按钮的基本功能,然后我们再添加或修改特定的功能和样式。
# 伪代码示例
# class MyFancyButton(tkinter.Button):
# def __init__(self, master, **kwargs):
# super().__init__(master, **kwargs)
# # 添加自定义样式或行为
# self.config(fg="red", font=("Arial", 16))
#
# def on_click(self): # 重写或新增点击事件
# print("你点击了我的花哨按钮!")
4.1.2 Web 框架开发
在使用 Django 或 Flask 等 Web 框架时,我们定义的模型(Model)通常继承自框架的 models.Model 基类,视图(View)继承自 views.View 基类。这使得我们的类自动拥有了数据库操作、HTTP 请求处理等复杂能力。
# Django 伪代码示例
# from django.db import models
#
# class BlogPost(models.Model): # 继承自框架的 Model 基类
# title = models.CharField(max_length=200)
# content = models.TextField()
# pub_date = models.DateTimeField('date published')
# # 自动获得了保存、删除、查询等数据库操作方法
4.1.3 游戏开发
在游戏中,可以定义一个 GameObject 父类,包含所有游戏对象共有的属性(如位置 x, y)和方法(如 update(), draw())。然后创建 Player, Enemy, Bullet 等子类继承它,并各自实现独特的 update 和 draw 逻辑。
五、总结
本文详细介绍了 Python 面向对象编程中的继承机制,它是实现代码复用和构建清晰类层次结构的关键。
- 核心概念:继承允许一个子类获取父类的属性和方法,如同子女继承父母的特征。这体现了 “is-a” 的关系。
- 核心价值:主要在于代码复用和构建逻辑清晰的类层次结构,极大地提升了代码的可维护性和可扩展性。
- 基本语法:通过
class ChildClass(ParentClass):的形式实现单继承。子类实例在创建时会自动调用父类的__init__方法(如果子类没有重写它)。 - 方法重写 (Method Overriding):当父类方法不满足子类需求时,子类可以定义一个同名方法来覆盖父类的实现,从而实现特有的行为。
- 后续展望:本次我们学习了最基本的单继承。在下一篇文章中,我们将继续深入探讨继承的高级主题:如何在使用方法重写的同时,还想调用父类被覆盖掉的方法?这就需要用到
super()函数。此外,我们还将探索一个类继承多个父类的场景——多重继承。
:代码复用与扩展的艺术&spm=1001.2101.3001.5002&articleId=149431100&d=1&t=3&u=0e9b5a45780345bc8caa1351e3a83a06)
6万+

被折叠的 条评论
为什么被折叠?



