Skip to content

类与对象 ​

前面我们已经学了变量、流程控制和函数,也在函数化学生信息管理系统中用字典保存学生信息,再用函数处理这些数据。

这种写法可以完成任务。不过,当学生越来越多、功能越来越复杂时,数据和处理数据的函数会逐渐分散。如何让同一类数据保持统一结构,并让处理这些数据的功能与数据放在一起?

本节继续使用“学生成绩”场景,对比面向过程和面向对象两种写法,认识类与对象。

需求:用同一组学生成绩数据完成信息展示,并比较两种代码组织方式的差异。

功能分析:先理解对象如何保存数据和提供功能,再用 Student 类创建对象,观察数据与方法如何组合。

面向对象模型 ​

面向对象概念

面向对象的英文是 Object-Oriented Programming,简称 OOP。

先不用急着背定义,可以把它理解成:

把现实中的事物抽象成程序里的对象,再让对象完成自己的事情。

例如:

  • 一个人
  • 一本书
  • 一辆车
  • 一个学生

这些事物都可以抽象成对象。

认识对象,可以从两个角度入手。

对象抽象

以“人”为例,每个人都有自己的信息:

  • 姓名
  • 年龄
  • 身高
  • 体重

人还可以完成一些行为:

  • 吃饭
  • 睡觉
  • 跑步

程序里的对象也是如此:它既可以保存数据,也可以提供处理这些数据的功能。

从现实事物到程序对象抽象映射

属性与方法

对象里通常会放两类内容:

  1. 属性:表示对象的数据状态
  2. 方法:表示对象能够完成的操作

例如,一个学生对象可以包含:

  • 属性:姓名、成绩
  • 方法:打印成绩、修改成绩

可以先简单记成:

对象把相关的数据和功能放到了一起。

对象的属性与方法

类的抽象与实例化

类是同一类事物的抽象模板,对象是根据这个模板创建出来的具体个体。

例如:

text
类:人
对象:正心、小明、小红

同一个类可以创建多个对象,每个对象又可以保存自己的数据。

可以这样区分:

  • 类:描述这一类事物共同具有的特征和行为
  • 对象:按照类创建出来的具体某一个

类与对象的实例化关系

编程组织方式对比 ​

这两个概念比较抽象,先从关注点来区分。

面向过程:执行步骤

面向过程会把完成任务的步骤依次写出来,关注的是:

先做什么,再做什么,最后做什么。

面向对象:角色职责

面向对象会先划分角色和职责,再让不同对象完成自己的任务,关注的是:

谁来做这件事。

可以先这样记:

  • 面向过程:关注“怎么做”
  • 面向对象:关注“谁来做”

面向对象并不会替代面向过程。对象的方法内部仍然要一步步执行代码,只是数据和功能的组织方式不同。

面向过程与面向对象的组织方式对比

面向对象特征 ​

面向对象通常会涉及三个特点:

  1. 封装
  2. 继承
  3. 多态

后面的课程会逐步展开。本节先理解“封装”:把相关的数据和功能组织到一起。

案例:学生成绩对象建模 ​

在 Python 里,所有数据都可以看成对象。我们自己定义一个类,相当于定义一种新的对象类型。

接下来使用同一组学生数据,对比两种代码组织方式。

需求:分别使用字典与函数、类与对象打印两名学生的成绩,比较两种写法中数据与处理功能的组织方式。

功能分析:先用字典保存数据并由外部函数处理,再定义 Student 类,把姓名、成绩和打印成绩的方法组合到对象中。

方案一:字典与函数 ​

先使用字典保存两名学生的数据:

python
student1 = {"name": "小明", "score": 98}
student2 = {"name": "小红", "score": 81}

再定义一个函数,用来打印学生成绩:

python
def print_score(student):
    print(f"姓名:{student['name']}  成绩:{student['score']}")


print_score(student1)
print_score(student2)

运行结果:

text
姓名:小明  成绩:98
姓名:小红  成绩:81

这种写法没有问题,小项目里完全可以使用。

不过,字典只负责保存数据,函数单独放在外面。调用函数时,还要主动把对应的学生数据传进去。

方案二:类与对象 ​

换成面向对象思路,我们会先思考:

“学生”是否应该有一个统一模板,并且由学生自己打印成绩?

这个模板需要规定两类内容:

  • 学生具有姓名和成绩
  • 学生可以打印自己的成绩

于是可以抽象出一个 Student 类。

类定义

python
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print_score(self):
        print(f"姓名:{self.name}  成绩:{self.score}")

这里先认识代码的整体结构:

  1. class 用来定义类
  2. Student 是类名,通常使用大驼峰命名
  3. __init__() 用来初始化对象
  4. self.name、self.score 是对象自己的属性
  5. print_score() 是对象的方法

对象实例化

类定义好后,就可以根据类创建具体对象:

python
student1 = Student("小明", 98)
student2 = Student("小红", 81)

这一步叫作实例化。也就是根据 Student 模板,创建两个具体的学生对象。

属性与方法调用

可以直接访问对象的属性,也可以让对象调用自己的方法:

python
print(f"姓名:{student1.name}")
print(f"成绩:{student1.score}")

student1.print_score()
student2.print_score()

运行结果:

text
姓名:小明
成绩:98
姓名:小明  成绩:98
姓名:小红  成绩:81

观察这段代码:

  • student1 和 student2 都来自 Student 类
  • 两个对象分别保存自己的姓名和成绩
  • 调用 student1.print_score() 时,打印的是 student1 自己的数据

这样一来,学生数据和打印成绩的方法就组织到了一起,它们之间的关系也更清楚。

下一节继续

这里先看类和对象的完整形态。__init__()、self 和实例属性的具体工作过程,会在下一节继续拆解。

类与对象速查 ​

先记住三个步骤:

  1. 抽象出类
  2. 根据类创建对象
  3. 让对象完成自己的工作

面向对象实战三步法全景闭环

对应到学生成绩案例:

代码作用
Student学生类,表示统一模板
student1、student2根据类创建的对象
print_score()对象可以调用的方法

函数主要封装完成任务的步骤,类和对象还可以把数据与处理数据的方法组织到一起。当项目中的数据和功能越来越多时,这种组织方式可以让它们的关系更清晰,也更容易继续扩展。

小结 ​

本节重点掌握四件事:

  1. 类是一类事物的抽象模板
  2. 对象是根据类创建出来的具体实例
  3. 对象通常包含属性和方法
  4. 面向对象的核心是把相关的数据和功能组织到一起

练习 ​

  1. 自己举出 3 组“类”和“对象”的例子
  2. 用字典表示一个学生,再思考它和 Student 对象有什么区别
  3. 尝试编写一个 Dog 类,保存小狗的名字,并提供一个“叫”的方法