Python 类入门:从“字典堆字典”到“面向对象”,看类的三大优势如何碾压原始写法
目录
一、从一个小需求说起:管理学生信息
假设我们要做一个学生成绩管理系统,最开始的需求很简单:
-
存储学生的姓名、年龄、成绩;
-
能修改学生的成绩;
-
能打印学生的基本信息。
不用类的写法:字典套字典,越写越混乱
新手最容易想到的方式是用字典存储每个学生的信息,再用一个列表存所有学生:
# 不用类:用字典存学生信息
students = [
{"name": "小明", "age": 18, "score": 85},
{"name": "小红", "age": 19, "score": 92},
{"name": "小刚", "age": 17, "score": 78}
]
# 修改小明的成绩 → 得精准定位字典键
students[0]["score"] = 90 # 靠索引找小明,容易写错!
# 打印小明的信息 → 写死逻辑
print(f"姓名:{students[0]['name']},年龄:{students[0]['age']},成绩:{students[0]['score']}")
这段代码的问题在哪里?
-
可读性差:
students[0]到底是谁?全靠注释或记忆,后期维护想改小明的信息都怕改错; -
重复劳动:打印每个学生都要写一遍
f-string,新增“性别”属性时,所有打印逻辑都要改; -
数据不安全:直接修改字典的
score键,没有任何校验(比如成绩能不能超过100?负数怎么办?); -
扩展困难:如果要加“研究生”类型(需要额外存“论文题目”),得重新写一套字典结构,完全无法复用之前的代码。
用类的写法:封装数据与行为,代码瞬间“清爽”
类的核心是封装——把“学生”的数据(姓名、年龄、成绩)和行为(修改成绩、打印信息)绑在一起,形成一个独立的“学生对象”。
第一步:定义 Student 类
class Student:
# 1. 初始化方法:创建对象时自动设置属性
def __init__(self, name: str, age: int, score: float):
self.name = name # 实例属性:每个学生独有的姓名
self.age = age # 实例属性:每个学生独有的年龄
self.score = score # 实例属性:每个学生独有的成绩
# 2. 方法:修改成绩(带校验,保护数据安全)
def update_score(self, new_score: float):
if not (0 <= new_score <= 100):
raise ValueError("成绩必须在 0-100 之间!")
self.score = new_score
print(f"{self.name}的成绩已更新为:{new_score}")
# 3. 方法:打印学生信息(封装输出逻辑)
def get_info(self) -> str:
return f"【学生】姓名:{self.name} | 年龄:{self.age} | 成绩:{self.score}"
第二步:用类创建对象,操作更丝滑
# 创建学生对象 → 每个对象都是独立的“学生实体”
xiaoming = Student("小明", 18, 85)
xiaohong = Student("小红", 19, 92)
xiaogang = Student("小刚", 17, 78)
# 修改小明的成绩 → 直接调用对象的方法,无需记索引
xiaoming.update_score(90) # 输出:小明的成绩已更新为:90
# 打印小红的信息 → 调用对象的 get_info 方法
print(xiaohong.get_info()) # 输出:【学生】姓名:小红 | 年龄:19 | 成绩:92
对比总结:类的第一个优势——封装性
不用类时,数据和行为是分离的(字典存数据,函数处理行为);
用类后,数据和行为被打包成一个对象,既保证了数据的完整性,又让代码逻辑更集中。
二、类的第二个优势:代码复用与扩展
假设需求升级了:要支持研究生信息管理,除了姓名、年龄、成绩,还需要存“论文题目”。
不用类的写法:复制粘贴,代码冗余
# 研究生字典 → 几乎复制了学生的结构,只加了 thesis
grad_students = [
{"name": "小李", "age": 20, "score": 88, "thesis": "AI在医疗中的应用"},
{"name": "小王", "age": 21, "score": 95, "thesis": "区块链安全研究"}
]
# 打印研究生信息 → 重复写 f-string
def print_grad_info(grad):
return f"【研究生】姓名:{grad['name']} | 年龄:{grad['age']} | 成绩:{grad['score']} | 论文:{grad['thesis']}"
用类的写法:继承复用,轻松扩展
类的继承特性允许我们基于现有类(父类)创建新类(子类),复用父类的代码,只添加新的功能。
# 父类:Student(已有的学生类)
class GraduateStudent(Student): # 继承 Student 类
def __init__(self, name: str, age: int, score: float, thesis: str):
super().__init__(name, age, score) # 调用父类的初始化方法,复用姓名、年龄、成绩
self.thesis = thesis # 子类独有的属性:论文题目
# 重写父类的 get_info 方法,扩展输出内容
def get_info(self) -> str:
base_info = super().get_info() # 调用父类的 get_info 方法,复用基础信息
return f"{base_info} | 论文:{self.thesis}" # 添加论文信息
使用研究生对象:
# 创建研究生对象 → 自动拥有 Student 的属性和方法
xiaoli = GraduateStudent("小李", 20, 88, "AI在医疗中的应用")
# 打印信息 → 复用了 Student 的 get_info,同时扩展了论文
print(xiaoli.get_info())
# 输出:【学生】姓名:小李 | 年龄:20 | 成绩:88 | 论文:AI在医疗中的应用
对比总结:类的第二个优势——继承与复用
不用类时,新增类型要复制粘贴所有代码,冗余且易出错;
用类时,通过继承复用父类代码,只修改新增部分,代码量减少80%以上,且更易维护。
三、类的第三个优势:多态,统一接口不同实现
假设我们需要一个函数,打印所有学生(包括本科生和研究生)的信息。
不用类的写法:判断类型,代码臃肿
def print_all_info(students):
for s in students:
if "thesis" in s: # 判断是不是研究生
print(f"【研究生】姓名:{s['name']} | ... | 论文:{s['thesis']}")
else:
print(f"【学生】姓名:{s['name']} | ... | 成绩:{s['score']}")
用类的写法:多态,统一接口
类的多态特性允许不同子类重写父类的方法,从而实现“同一接口,不同行为”。
我们已经有:
-
Student的get_info方法返回本科生信息; -
GraduateStudent的get_info方法返回研究生信息(重写了父类方法)。
因此,打印所有信息的函数可以统一调用 get_info,无需判断类型:
def print_all_info(person_list):
for p in person_list:
print(p.get_info()) # 不管是学生还是研究生,都有 get_info 方法!
测试效果:
# 把本科生和研究生放在同一个列表里
all_persons = [xiaoming, xiaohong, xiaogang, xiaoli]
# 统一打印 → 自动调用各自的 get_info 方法
print_all_info(all_persons)
输出:
【学生】姓名:小明 | 年龄:18 | 成绩:90
【学生】姓名:小红 | 年龄:19 | 成绩:92
【学生】姓名:小刚 | 年龄:17 | 成绩:78
【学生】姓名:小李 | 年龄:20 | 成绩:88 | 论文:AI在医疗中的应用
对比总结:类的第三个优势——多态性
不用类时,处理不同类型要写一堆判断逻辑,代码冗余且难扩展;
用类时,通过统一接口(get_info)调用不同实现,代码简洁且易新增类型。
四、类的终极优势:让代码更“像人一样思考”
其实,类的本质是对现实世界的建模:
-
学生是一个“对象”,有属性(姓名、年龄)和行为(修改成绩、打印信息);
-
研究生是“学生”的一种,继承了学生的属性,又有自己的额外属性(论文)。
用类的方式写代码,就像在描述现实中的事物:
“我有一个学生叫小明,他18岁,成绩90分,我可以修改他的成绩,也可以打印他的信息。”
而不用的类的方式,更像在操作“数据仓库”:
“我要从字典里找小明的条目,修改他的成绩键,再拼接字符串打印。”
五、什么时候该用类?
类不是万能的,以下场景建议用类:
-
数据有状态:比如学生有成绩,修改成绩会影响对象的状态;
-
需要封装:不想让外部直接修改内部数据(比如成绩要做校验);
-
需要复用:多个类型有共同的属性和行为(比如学生和研究生);
-
需要多态:不同类型需要统一的接口(比如打印所有人的信息)。
六、总结:类的价值在于“组织代码”
类的核心不是“语法”,而是组织代码的方式:
-
用封装保护数据安全;
-
用继承复用代码;
-
用多态简化逻辑。
回到最初的需求,用类后的代码:
-
更易读:每个对象代表一个具体的学生;
-
更易维护:修改属性或行为只需改类内部;
-
更易扩展:新增研究生只需继承父类。
如果你还在用“字典套字典”写代码,不妨试试用类重构——你会发现,代码瞬间从“混乱的仓库”变成了“有序的工厂”!
最后留个小练习:
试试用类实现一个“猫的饲养系统”,要求:
-
猫有名字、年龄、品种;
-
能喂猫(修改饱食度);
-
能打印猫的信息;
-
新增“布偶猫”类型,继承自猫,添加“毛色”属性。
欢迎在评论区分享你的代码~
关注我,后续会写更多Python面向对象的高级技巧(比如魔法方法、类属性、静态方法)!
更多推荐



所有评论(0)