学习目标
- 理解什么是面向对象编程。
- 区分类、对象、属性、方法的概念。
- 能够使用 Python 定义类并创建对象。
- 理解
self的作用。 - 掌握构造方法
__init__的使用。 - 理解封装、继承、多态三大核心思想。
- 能够用面向对象思想解决简单实际问题。
为什么需要面向对象
面向过程
面向过程的核心思想是:自顶向下,逐步细化。
特点:
- 把问题拆成一个个步骤
- 每个步骤用函数实现
- 按顺序执行
示例(报名流程):
开始 → 提交信息 → 缴费 → 分班 → 结束
问题:
- 数据与行为分离
- 难以维护复杂系统
面向对象
核心思想:
不再关注“做什么步骤”,而是关注“谁来做这些事情”
例如报名系统可以抽象为4个对象:
- 学生
- 教师
- 大学
- 班级
每个对象:
- 有属性(数据)
- 有方法(行为)
核心对比
| 维度 | 面向过程 | 面向对象 |
|---|---|---|
| 思维方式 | 步骤导向 | 对象导向 |
| 复杂系统 | 难维护 | 易扩展 |
| 代码复用 | 较低 | 更高 |
什么是类和对象
对象
对象是现实世界中具体存在的一个事物。
例如:
- 一个具体的学生:张三
- 一辆具体的汽车:我的白色汽车
- 一只具体的猫:小花
- 一个具体的订单:订单编号 1001
在程序中,对象通常包含两部分:
| 组成 | 含义 | 示例 |
|---|---|---|
| 属性 | 对象的数据、特征 | 姓名、年龄、颜色 |
| 方法 | 对象的行为、功能 | 学习、跑步、打印信息 |
类
类是对象的模板或设计图。
例如:
- “学生类”是所有学生的模板
- “汽车类”是所有汽车的模板
- “猫类”是所有猫的模板
类和对象的关系可以这样理解:
| 类 | 对象 |
|---|---|
| 图纸 | 根据图纸造出来的房子 |
| 模板 | 根据模板创建出来的具体内容 |
| 学生类 | 张三、李四、王五 |
| 汽车类 | 宝马、奔驰、比亚迪 |
一句话总结:
类是抽象的,对象是具体的。
定义类和创建对象
定义一个最简单的类
1 | class Student: |
说明:
class是定义类的关键字。Student是类名,通常使用大驼峰命名法。pass表示暂时不写内容。
创建对象
1 | stu1 = Student() |
stu1 和 stu2 都是通过 Student 类创建出来的对象。
它们属于同一个类,但它们是两个不同的对象。

给对象添加属性
对象的属性可以理解为对象的数据。
1 | ''' |
输出:
1 | 张三 |
这种方式可以添加属性,但不推荐在正式项目中大量使用,因为每个对象的属性可能不统一。
例如:
1 | stu1.name = "张三" |
这样会导致对象结构混乱。
更推荐使用构造方法 __init__ 来统一初始化属性。
构造方法
什么是构造方法
构造方法是在创建对象时自动执行的方法。
在 Python 中,构造方法的名字固定为:
1 | __init__ |
示例:
1 | class Student: |
输出:
1 | 张三 18 |
self` 是什么
self 表示当前对象本身。
当执行:
1 | stu1 = Student("张三", 18) |
可以理解为:
1 | self 指向 stu1 |
当执行:
1 | stu2 = Student("李四", 19) |
可以理解为:
1 | self 指向 stu2 |
所以 self 的作用是:
区分当前操作的是哪一个对象。

常见错误
错误写法:
1 | class Student: |
问题:
- 少写了
self。 - 没有把数据保存到对象中。
name = name只是局部变量赋值,没有意义。
正确写法:
1 | class Student: |
对象方法
方法就是定义在类中的函数,用来描述对象的行为。
1 | ''' |
输出:
1 | 大家好,我叫张三,今年18岁 |
说明:
introduce是对象方法。- 对象方法的第一个参数通常也是
self。 - 调用方法时,不需要手动传入
self。
也就是说:
1 | stu1.introduce() |
Python 会自动把 stu1 传给 self。

完整示例:学生类
1 | class Student: |
输出:
1 | 大家好,我叫张三,今年18岁 |
类属性和实例属性
实例属性
实例属性属于具体对象,每个对象可以拥有不同的值。
1 | class Student: |
这里的 name 就是实例属性。
类属性
类属性属于类本身,所有对象可以共享。
1 | class Student: |
输出:
1 | 第一中学 |
类属性和实例属性的区别
| 类型 | 所属对象 | 是否共享 | 示例 |
|---|---|---|---|
| 实例属性 | 具体对象 | 不共享 | self.name |
| 类属性 | 类本身 | 共享 | Student.school |
示例:统计学生人数
1 | class Student: |
输出:
1 | 3 |
封装
什么是封装
封装是指把数据和操作数据的方法放在一起,并对外隐藏不希望直接访问的细节。
简单理解:
不让外部随便修改对象内部的数据,而是通过方法来控制访问。
例如,学生成绩不应该被随意设置为负数。
未封装的问题
1 | class Student: |
输出:
1 | -100 |
这显然不合理。
使用私有属性
在 Python 中,属性名前面加两个下划线,表示私有属性。
1 | class Student: |
输出:
1 | 90 |
封装的好处
- 保护数据安全。
- 控制数据修改规则。
- 降低外部代码对内部实现的依赖。
- 让类的使用更加清晰。
继承
本质理解(结合哲学)
继承本质是:共性 + 个性
例如:
生物 → 动物 → 哺乳动物 → 人类
- 上层:共性
- 下层:个性
继承核心作用
- 代码复用
- 表达层级关系
- 提升扩展能力
基本语法
1 | class 父类: |
经典案例(强化)
1 | ''' |
__init__流程说明
1 | # 动物类 |

方法覆盖
1 | # 动物类 |
通过子类调用父类方法
1 | # 动物类 |
私有成员说明(进阶重点)
父类私有方法:
1 | def __private_func(self): |
特点:
- 子类不能直接访问
- 本质被改名:_类名__方法名
1 | # 动物类 |
多继承
Python 支持多继承:
1 | class A: |
输出:
1 | A |
为什么不是 B?
因为 Python 会按照 MRO(Method Resolution Order,方法解析顺序) 查找方法。
查看 MRO:
1 | print(C.__mro__) |
输出类似:
1 | (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) |
所以查找顺序是:
1 | C → A → B → object |
小结
- 多继承时,方法查找不是随便找的
- Python 按照 MRO 顺序查找方法
类名.__mro__可以查看查找顺序- 初学者应先掌握单继承,再理解多继承和 MRO
方法重写
什么是方法重写
如果子类对父类的方法不满意,可以在子类中重新定义同名方法。
这叫方法重写。
1 | ''' |
输出:
1 | 我是一只小狗,我叫旺财 |
为什么需要方法重写
不同子类虽然拥有相同的方法名,但具体表现可能不同。
例如:
- 狗会叫,但叫声是“汪汪”。
- 猫会叫,但叫声是“喵喵”。
- 鸭子会叫,但叫声是“嘎嘎”。
这为多态打下了基础。
调用父类方法
有时子类并不是完全替换父类方法,而是在父类原有功能基础上增加新功能。
这时可以使用 super()。
正确完整代码:
1 | ''' |
输出:
1 | 我是一只动物,我叫旺财 |
说明:
super().__init__(name)调用了父类的构造方法。super().introduce()调用了父类的introduce方法。

另外一种调用方式
1 | ''' |
多继承风险
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 >'''
>需求:
>1. 定义一个汽车Car基类,构造方法__init__接受汽车的名字和颜色
>2. 定义GasolineCar类,继承自Car, 实现__init__方法,接受参数名字,颜色
以及充能方式
实现run方法,输出耗油运行
实现energy方法,输出默认使用燃油
>3. 定义ElectricCar类, 实现__init__方法,接受参数名字,颜色
以及充能方式
继承自Car,实现run方法,输出耗电运行
实现energy方法,输出默认使用电能
>4. 定义HybridCar类,同时继承自ElectricCar,GasolineCar,
>实现run方法,油电混动运行
>5. 实例化一个HybridCar对象,调用energy以及run方法,看看输出
>'''
代码
1 | ''' |
如果HybridCar没有实现
__init__方法, 将会导致通过mro顺序调用上一级的__init__方法而上一级是ElectricCar类,ElectricCar类的
__init__方法内部又调用了super()所以会通过mro找到上一级这个上一级其实是GasolineCar, 进而造成
__init__调用参数不匹配而失败规避的方式第一种即使实现HybridCar的
__init__方法第二种方式就是通过父类名.方法名方式显示调用
第二种方式
1 | ''' |
结论
当使用多继承时,子类调用父类的方法,一定要用父类名.方法名(参数1,参数2…)
多态
什么是多态
多态是指不同对象调用相同方法时,表现出不同的行为。
核心特点:
相同的方法名,不同的实现效果。
1 | ''' |
输出:
1 | 我叫动物, 通过动物咆哮 |
多态的优势
多态可以让代码更加灵活。可以将抽象类的定义和具体类的实现分离,实现开发的解耦合
同时使用平台,不用随着逻辑的变化而修改,将来只要扩充子类类型即可。
符合高内聚和低耦合的思想。
例如:
1 | def make_sound(animal): |
这个函数不关心传入的是狗、猫还是鸭子,只关心对象有没有 speak 方法。
like方式继承
like方式就是像的意思,不要求类一定和某一个类实现继承关系,只要这个类具备相似的方法即可。
1 | ''' |
王者荣耀换肤案例
1 | ''' |
特殊方法
Python 中有一些以双下划线开头和结尾的方法,称为特殊方法,也叫魔术方法。
__str__
当使用 print() 打印对象时,会自动调用对象的 __str__ 方法。
1 | class Student: |
输出:
1 | 学生姓名:张三,年龄:18 |
如果不定义 __str__,直接打印对象通常会看到对象的内存地址信息,不利于阅读。
__repr__
__repr__ 更偏向开发者调试使用,通常返回一个更明确的对象描述。
1 | class Student: |
输出:
1 | Student(name='张三', age=18) |
类方法和静态方法
实例方法
最常见的方法是实例方法,第一个参数是 self。
1 | class Student: |
实例方法通常需要访问对象本身的数据。
类方法
类方法使用 @classmethod 装饰器,第一个参数通常是 cls,表示当前类。
1 | class Student: |
输出:
1 | 当前学生人数:2 |
静态方法
静态方法使用 @staticmethod 装饰器。
它不需要访问对象,也不需要访问类。
1 | class MathTool: |
输出:
1 | 8 |
三种方法对比
| 方法类型 | 第一个参数 | 是否访问实例属性 | 是否访问类属性 |
|---|---|---|---|
| 实例方法 | self |
可以 | 可以 |
| 类方法 | cls |
不直接访问 | 可以 |
| 静态方法 | 无固定参数 | 不访问 | 不访问 |
面向对象综合案例:银行账户
需求分析
设计一个银行账户类 BankAccount,要求:
- 每个账户有账户名和余额。
- 可以存款。
- 可以取款。
- 余额不能小于 0。
- 可以查看账户信息。
代码实现
1 | class BankAccount: |
输出:
1 | 账户名: zack, 余额: 1000 |
案例讲解重点
这个案例同时体现了:
- 类和对象。
- 构造方法。
- 实例属性。
- 私有属性。
- 封装思想。
- 方法对数据的控制。
课堂案例:图书管理
需求
- 设计一个图书管理系统
- 展示菜单
- 添加图书,包括作者,书名,价格,编号,数量
- 删除图书,根据编号和数量删除
- 修改图书信息
- 根据编号查看图书信息
- 将图书信息存储到本地文件
- 从本地文件将图书信息加载到内存
- 分页加载图书信息列表,根据页码加载
代码示例
1 | ''' |
课后作业
作业 1:商品类
定义一个 Product 类,要求:
- 有商品名称、价格、库存。
- 价格和库存不能为负数。
- 有展示商品信息的方法。
- 有购买商品的方法。
- 购买时库存减少。
- 如果库存不足,提示“库存不足”。
作业 2:学生管理小系统
定义一个 Student 类,包含:
- 姓名
- 年龄
- 成绩
再定义一个 StudentManager 类,包含:
- 添加学生
- 删除学生
- 查找学生
- 展示所有学生
作业 3:动物园案例
定义父类 Animal,包含:
- 名字
- 年龄
eat()方法speak()方法
定义子类:
DogCatBird
要求每个子类重写 speak() 方法。