第十一章 面向对象编程基础
Python 是一种典型的面向对象编程语言(OOP,Object-Oriented Programming)。从数据处理到函数封装,再到对象建模,体现了程序设计思想的逐步演进。
在面向对象的编程范式中,我们不再仅仅依赖函数操作数据,而是通过“对象”来统一管理数据与行为。每个对象既包含属性(用于描述状态),也具备方法(用于执行动作),从而使代码结构更清晰、易于复用和扩展。
学习目标:
- 理解类与对象的基本概念及其相互关系。
- 掌握如何定义类、创建实例,并使用属性与方法。
- 深入理解封装机制及信息隐藏的重要性。
- 了解继承机制与方法重写的设计思路。
- 认识多态性与抽象类背后的编程动机。
- 能够编写简单的面向对象程序,例如学生管理系统、图形建模或 AI 模型原型等应用。
11.1 面向对象编程概论
当程序规模逐渐扩大时,仅依靠变量、函数以及基本的数据结构(如列表、字典)已难以有效组织复杂逻辑。面向对象编程提供了一种更高层次的抽象方式,允许开发者使用“类”对现实事物进行建模,并通过“对象”表示具体的实例。
对象具有两个核心特征:
- 属性(Attributes):用于描述对象的状态或所拥有的数据。
- 方法(Methods):表示对象能执行的操作或行为。
OOP 不仅关注数据本身,更强调对象的职责与交互方式。
面向对象的四大核心特性包括:
- 抽象(Abstraction):聚焦于“做什么”,而非“如何做”。通过隐藏实现细节,只暴露必要的接口。
- 封装(Encapsulation):将数据和操作数据的方法捆绑在一起,形成独立模块,提升可维护性和安全性,是实现抽象的关键手段。
- 继承(Inheritance):支持代码复用和层级化设计。通用功能可提取至父类,子类负责实现具体差异。
- 多态(Polymorphism):同一接口可被不同类以各自的方式实现。调用相同方法时,会根据实际对象类型自动执行对应的行为。
借助抽象、封装、继承和多态,OOP 将复杂的系统划分为多个高内聚、低耦合的模块,显著增强了程序的结构性、可读性与可扩展性。
掌握面向对象编程,意味着具备了拆解大型问题、构建可持续发展系统的思维能力,是现代软件开发不可或缺的核心素养。
11.2 类与对象
11.2.1 基本概念
类(Class)是对某一类事物的抽象模板,定义了该类所有实例共有的结构与行为。
对象(Object / Instance)是类的具体实现,是一个可以被操作的实际实体。
举例说明:
- 类:Student
- 对象:某位具体的学生,如“艾婉婷”
在 Python 中,“一切皆为对象”——无论是整数、字符串、函数、模块,还是类本身,都是对象的一种表现形式。
class?Dog: ? ? ? ? ? ? ? ? ? ??# 定义类? ??def?bark(self): ? ? ? ? ? ?# 定义实例方法? ? ? ? print("汪汪!")
d =?Dog() ? ? ? ? ? ? ? ? ? ? ?# 创建对象(实例化)d.bark() ? ? ? ? ? ? ? ? ? ? ??# 调用方法# 输出:汪汪!
11.2.1.1 类的定义
使用 class 关键字来定义一个类:
class?ClassName:? ??"""类的说明信息"""? ??# 类文档字符串,可选
? ??# 类体内容:类变量、实例变量以及方法等定义语句
建议类名采用“大写字母开头的驼峰命名法”,例如 Student、Teacher 或 AIModel。
类体不能为空。若暂时未确定具体属性与方法,可用 pass 语句作为占位符:
class?Empty:? ??pass
11.2.1.2 实例化与初始化方法
利用已定义的类生成具体对象的过程称为“实例化”:
变量名 = 类名(参数列表)
括号内的参数会被传递给类中的 __init__() 方法。
注意事项:
__init__是初始化方法,在对象创建后自动执行,用于设置初始状态;- 真正的对象构造由
__new__完成,通常无需手动重写,除非涉及自定义内存分配或不可变类型的初始化。
示例:
class?Student:? ??"""学生类"""
? ??def?__init__(self, name, score): ??# 初始化方法? ? ? ??self.name = name ? ? ? ? ? ? ??# 学生姓名(实例属性)? ? ? ??self.score = score ? ? ? ? ? ??# 学生成绩(实例属性)
? ??def?show(self): ? ? ? ? ? ? ? ? ? ?# 实例方法? ? ? ??print(f"{self.name}?的成绩是?{self.score}?分。")
# 创建学生对象stu1 = Student("艾婉婷",?95)# 调用实例方法stu1.show()# 输出:艾婉婷 的成绩是 95 分。
说明:
self 并非关键字,而是约定俗成的参数名称,代表当前实例对象。Python 会在调用实例方法时自动传入该参数,用于访问该实例的属性和方法。
11.2.2 实例属性与类属性
类的属性主要分为两类:类属性和实例属性。
11.2.2.1 类属性
类属性是在类体内直接定义的变量,位于类的作用域顶层。
例如:
class?X:? ??shared?= []
类属性属于类本身,所有该类的实例共享同一份数据。
说明:
- 可通过
类名.属性名的方式直接访问或修改类属性。 - 如果通过
实例.属性名 = 值的形式赋值,则不会更改类属性,而是在该实例上创建一个同名的实例属性,从而覆盖(屏蔽)类属性。 - 若类属性指向的是可变对象(如 list、dict),则所有实例共享该对象。一旦某个实例修改了该对象,其他实例也会受到影响。
示例(警示):
class?X:? ??shared?= []
x1?=?X(); x2 = X()x1.shared.append(1)print(x2.shared) ?# 会看到 [1]
因此,若希望每个实例拥有独立的可变数据,应在 __init__() 方法中创建实例属性。
11.2.2.2 实例属性
实例属性通常在 __init__() 方法中定义,用于保存特定于某个对象的数据。
<self.属性名>?=?<值>
这类属性描述的是个体特征,每个实例都拥有自己独立的副本。
说明:
- 可通过
实例.属性名访问其属性值。 - 当执行
实例.属性名 = 值时,若属性已存在则更新,否则动态创建新的实例属性(即使存在同名的类属性)。
示例:
class?Robot:? ? category =?"AI"? ? ? ? ? ?# 类属性(所有机器人共享)
? ??def?__init__(self, name):? ? ? ??self.name = name ? ? ?# 实例属性
r1 = Robot("Alpha")r2 = Robot("Beta")
print(r1.category, r2.category) ?# 都能访问类属性print(r1.name, r2.name) ? ? ? ? ?# 各自的实例属性不同
# 动态添加实例属性r1.color =?"red"? ? ? ? ? ? ?r2.weight =?50.0? ? ? ? ? ? ?
print(r1.color) ? ? ? ? ? ? ??# 输出: redprint(r2.weight) ? ? ? ? ? ? ?# 输出: 50.0
# 实例属性屏蔽类属性r1.category =?"Advanced AI"? ?# 为r1创建同名实例属性,屏蔽类属性print(r1.category) ? ? ? ? ? ?# 输出: Advanced AI (实例属性)print(r2.category) ? ? ? ? ? ?# 输出: AI (仍然访问类属性)print(Robot.category) ? ? ? ??# 输出: AI (类属性本身不变)
11.2.2.3 属性查找顺序
当访问某个属性时,Python 按照以下顺序进行查找:
实例属性 → 类属性 → 父类(遵循 MRO 顺序)→ object
在使用多重继承时,基类的查找顺序由 MRO(Method Resolution Order,方法解析顺序)决定。这一机制确保了方法调用的路径清晰且无歧义。
11.2.3 实例方法、类方法与静态方法
类中定义的方法类型主要依据其第一个参数的不同而区分,分别对应实例方法、类方法和静态方法,各自承担不同的职责。
11.2.3.1 实例方法
实例方法至少包含一个参数,通常命名为 self,用于指向调用该方法的具体对象实例。
这类方法最常通过对象来调用,如:obj.method(),主要用于访问或修改对象的状态信息。
class?Counter:? ??def?__init__(self):? ? ? ??self.count =?0
? ??def?increment(self):? ? ? ??self.count +=?1
c1 =?Counter()for?_?in?range(5):? ? c1.increment()print(c1.count)
此外,实例方法也可以通过类本身进行调用,但此时必须显式传入一个有效的实例作为参数,例如:
Counter.increment(c1)
这种方式虽然在调试或元编程场景下有一定用途,但在常规开发中并不推荐使用。
def?method(self, ...):? ??# self 指向实例本身
11.2.3.2 类方法
类方法通过 @classmethod 装饰器定义,其第一个参数一般命名为 cls,代表类本身而非某个实例。
@classmethoddef?method(cls, ...):? ??# cls 指向类对象本身
由于拥有对类的引用,类方法可以操作类属性、调用其他类方法,适用于处理类级别的状态或逻辑。
它既可以通过类名调用,也可以通过实例调用。当通过实例调用时,Python 会自动将所属类作为 cls 参数传入,但从语义上建议优先使用类名调用来明确意图。
class?Counter:? ? total =?0
? ? @classmethod? ??def?show_total(cls):? ? ? ??print(f"当前计数器数量:{cls.total}")
Counter.total =?5Counter.show_total() ?# 当前计数器数量:5
示例应用包括实现备用构造函数、工厂模式等设计方式。
class?Person:? ??def?__init__(self, name, age):? ? ? ??self.name = name? ? ? ??self.age = age
? ??@classmethod? ??def?from_string(cls, s):? ? ? ? name, age = s.split(',')? ? ? ??return?cls(name, int(age))
p =?Person.from_string("艾婉婷,18")
11.2.3.3 静态方法
静态方法使用 @staticmethod 装饰器声明,不接收 self 或 cls 这类隐式参数,本质上是一个与类相关联的普通函数。
@staticmethoddef?method(...):? ? ...
它可以被类或其实例直接调用,行为不受调用者影响,适合封装那些逻辑上属于类范畴但无需访问实例或类数据的功能。
class?MathTool:? ? @staticmethod? ??def?add(x, y):? ? ? ??return?x + y
print(MathTool.add(3,?5)) ??# 通过类名调用
mytool = MathTool()print(mytool.add(5,3)) ? ? ?# 通过实例调用
常见用途包括工具函数、辅助计算或其他独立操作。
11.2.4 魔术方法
魔术方法(也称特殊方法或 Magic Methods)以双下划线开头和结尾,如 __init__、__str__、__eq__、__len__、__add__、__iter__ 等。
通过实现这些方法,可以让自定义类支持 Python 内建的操作语法,使对象表现得像原生数据类型一样自然。
class?Point:? ??def?__init__(self, x, y):? ? ? ??self.x,?self.y = x, y
? ??def?__str__(self): ? ??# 打印友好输出? ? ? ??return?f"Point({self.x},?{self.y})"
? ??def?__repr__(self): ? ?# 更适合开发者的表示? ? ? ??return?f"Point(x={self.x}, y={self.y})"
? ??def?__eq__(self, other): ?# == 比较逻辑? ? ? ??if?not?isinstance(other, Point):? ? ? ? ? ??return?NotImplemented? ? ? ??return?self.x == other.x?and?self.y == other.y
p1 = Point(1,?2)p2 = Point(1,?2)print(p1) ? ? ? ? ?# 调用 __str__()print(repr(p1)) ? ?# 调用 __repr__()print(p1 == p2) ? ?# 调用 __eq__()
输出结果如下所示:
Point(1,?2)Point(x=1, y=2)True
这些方法使得类能够支持运算符重载、迭代协议、上下文管理、属性访问控制等多种语言级行为,极大增强了对象的表现力和灵活性。
11.2.5 类与对象综合示例与应用
例 11.2.1:温度转换器类
项目说明:构建一个类,实现摄氏度与华氏度之间的相互转换功能。
class?Temperature:? ??def?__init__(self, celsius):? ? ? ??self.celsius = celsius
? ??def?to_fahrenheit(self):? ? ? ??return?self.celsius *?9?/?5?+?32
? ??def?show(self):? ? ? ? print(f"{self.celsius:.1f}°C = {self.to_fahrenheit():.1f}°F")
t =?Temperature(36.5)t.show()
运行输出:
36.5°C =?97.7°F
说明:该案例展示了如何在类中合理组织属性与方法,使对象具备自我处理数据的能力,体现了面向对象的核心思想。
例 11.2.2:AI 模型类
项目说明:定义一个名为 AIModel 的类,用于表示人工智能模型的基本信息及其推理行为。
class?AIModel:? ??def?__init__(self, name, version):? ? ? ??self.name = name? ? ? ??self.version = version
? ??def?predict(self, data):? ? ? ??print(f"[{self.name}?v{self.version}] 正在处理输入数据:{data}")
? ??def?info(self):? ? ? ??print(f"模型名称:{self.name}\n版本号:{self.version}")
model = AIModel("ImageNetClassifier",?"1.2")model.info()model.predict("[图片数据...]")
程序输出:
模型名称:ImageNetClassifier版本号:1.2[ImageNetClassifier v1.2]?正在处理输入数据:[图片数据...]
说明:利用类的封装特性,可有效管理模型的元数据与接口方法,是 AI 系统中常见的对象建模方式之一。
例 11.2.3:任务执行计数器
项目说明:设计一个计数器类,用于统计某项任务被执行的总次数。
class?TaskCounter:? ? total =?0? ?# 类属性:所有实例共享
? ??def?__init__(self, name):? ? ? ??self.name = name? ??? ??def?run(self):? ? ? ? TaskCounter.total +=?1? ? ? ??print(f"任务?{self.name}?已执行。")
? ? @classmethod? ??def?show_total(cls):? ? ? ??print(f"已执行任务总数:{cls.total}")
task1 = TaskCounter("数据清洗")task2 = TaskCounter("模型训练")task1.run()task2.run()TaskCounter.show_total()
输出结果:
任务 数据清洗 已执行。任务 模型训练 已执行。已执行任务总数:2
说明:此例结合了类属性与类方法的使用,适用于批量任务调度、日志追踪等需要共享状态记录的场景。
小结
本节内容系统介绍了面向对象编程的基本理念与核心组成要素。类是对现实事物的抽象建模,对象则是类的具体实例。通过 __init__ 方法完成初始化,借助实例属性与类属性区分个体状态与共享数据;通过实例方法、类方法和静态方法实现不同层级的功能划分;利用魔术方法让类更好地融入 Python 的对象体系。
类与对象为程序结构提供了更高层次的抽象能力,使开发者能以“事物”为中心组织代码逻辑,提升可读性与可维护性。
后续课程将深入探讨封装与继承机制,进一步构建结构清晰、可复用的对象层次体系。



雷达卡


京公网安备 11010802022788号







