目录

一、从一个小需求说起:管理学生信息

不用类的写法:字典套字典,越写越混乱

用类的写法:封装数据与行为,代码瞬间“清爽”

第一步:定义 Student 类

第二步:用类创建对象,操作更丝滑

对比总结:类的第一个优势——封装性

二、类的第二个优势:代码复用与扩展

不用类的写法:复制粘贴,代码冗余

用类的写法:继承复用,轻松扩展

使用研究生对象:

对比总结:类的第二个优势——继承与复用

三、类的第三个优势:多态,统一接口不同实现

不用类的写法:判断类型,代码臃肿

用类的写法:多态,统一接口

测试效果:

对比总结:类的第三个优势——多态性

四、类的终极优势:让代码更“像人一样思考”

五、什么时候该用类?

六、总结:类的价值在于“组织代码”


一、从一个小需求说起:管理学生信息

假设我们要做一个学生成绩管理系统,最开始的需求很简单:

  • 存储学生的姓名、年龄、成绩;

  • 能修改学生的成绩;

  • 能打印学生的基本信息。

不用类的写法:字典套字典,越写越混乱

新手最容易想到的方式是用字典存储每个学生的信息,再用一个列表存所有学生:

# 不用类:用字典存学生信息
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']}")

这段代码的问题在哪里?

  1. 可读性差students[0]到底是谁?全靠注释或记忆,后期维护想改小明的信息都怕改错;

  2. 重复劳动:打印每个学生都要写一遍f-string,新增“性别”属性时,所有打印逻辑都要改;

  3. 数据不安全:直接修改字典的score键,没有任何校验(比如成绩能不能超过100?负数怎么办?);

  4. 扩展困难:如果要加“研究生”类型(需要额外存“论文题目”),得重新写一套字典结构,完全无法复用之前的代码。

用类的写法:封装数据与行为,代码瞬间“清爽”

类的核心是封装——把“学生”的数据(姓名、年龄、成绩)和行为(修改成绩、打印信息)绑在一起,形成一个独立的“学生对象”。

第一步:定义 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']}")

用类的写法:多态,统一接口

类的多态特性允许不同子类重写父类的方法,从而实现“同一接口,不同行为”。

我们已经有:

  • Studentget_info方法返回本科生信息;

  • GraduateStudentget_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分,我可以修改他的成绩,也可以打印他的信息。”

而不用的类的方式,更像在操作“数据仓库”:

“我要从字典里找小明的条目,修改他的成绩键,再拼接字符串打印。”

五、什么时候该用类?

类不是万能的,以下场景建议用类:

  1. 数据有状态:比如学生有成绩,修改成绩会影响对象的状态;

  2. 需要封装:不想让外部直接修改内部数据(比如成绩要做校验);

  3. 需要复用:多个类型有共同的属性和行为(比如学生和研究生);

  4. 需要多态:不同类型需要统一的接口(比如打印所有人的信息)。

六、总结:类的价值在于“组织代码”

类的核心不是“语法”,而是组织代码的方式

  • 封装保护数据安全;

  • 继承复用代码;

  • 多态简化逻辑。

回到最初的需求,用类后的代码:

  • 更易读:每个对象代表一个具体的学生;

  • 更易维护:修改属性或行为只需改类内部;

  • 更易扩展:新增研究生只需继承父类。

如果你还在用“字典套字典”写代码,不妨试试用类重构——你会发现,代码瞬间从“混乱的仓库”变成了“有序的工厂”!

最后留个小练习

试试用类实现一个“猫的饲养系统”,要求:

  1. 猫有名字、年龄、品种;

  2. 能喂猫(修改饱食度);

  3. 能打印猫的信息;

  4. 新增“布偶猫”类型,继承自猫,添加“毛色”属性。

欢迎在评论区分享你的代码~

关注我,后续会写更多Python面向对象的高级技巧(比如魔法方法、类属性、静态方法)!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐