学径XUEJING · 个人学习平台通知设置

课程库 AI 主线 面向对象初步 › 第 2

类与对象 —— 属性和方法

普通课60 分钟

本课导读

上一课你见识了类的好,今天把语法正面讲透:class 怎么写、__init__ 在什么时候干什么、self 到底是谁(本课最大的拦路虎,一个类比放倒它)、属性和方法怎么配合。学完你能独立写出一个五脏俱全的类,并让 print 出来的对象说人话。预计 60 分钟。

最小的类,逐行拆

健身教练大壮要管理学员,从最小的类开始:

Python

逐行说清:

  • ① class 定义模具。类名用首字母大写的驼峰(TraineeTodoList)——这是社区约定,正好和蛇形的变量/函数区分开
  • __init__ 是出厂设置:名字怪(前后双下划线),身份特殊——你写 Trainee("小雨", 55) 时它自动执行,不用手动喊
  • self.name = name:把收到的参数存到对象身上,成为属性。存了,这个对象以后随时能用;不存,函数一结束参数就没了(局部变量,上单元讲过)
  • ④⑤⑥⑦ 造和用——注意造对象时不用传 self,下面马上解释

self 到底是谁

这是本课的大 boss,一个类比拿下:

提示

self 就是"我"这个代词。 模具(类)是给所有产品写的说明书,说明书里不能写死"小雨的体重",只能写"我的体重"(self.weight)。每个对象照着说明书行动时,"我"自动指向它自己——小雨的 report 里 self 是小雨,大壮的 report 里 self 是大壮。

Python

最后一行是"self 之谜"的官方答案:对象.方法() 时,Python 自动把点前面的对象塞给第一个参数 self。所以定义时写 self,调用时不用传——不是少了个参数,是 Python 替你传了。

说明

两个高频报错,现在就认识:忘写 self(def report():)→ 调用时 TypeError: report() takes 0 positional arguments but 1 was given——那个"多出来的 1"就是 Python 硬塞的对象本尊;方法里忘了 self.(直接写 name)→ NameError——不带 self 的是局部变量,不是属性。

属性会变:对象是活的

属性不是一次定终身——方法可以随时修改它,这正是"对象有状态"的意思:

Python

注意三件事:

  • self.sessions = 0——属性可以在 __init__直接给初值,不必都来自参数(回想上一课 Task 的 self.done = False
  • 方法能属性也能属性:train 每次都在更新 self 身上的数据
  • 方法照常支持上单元的功夫:默认参数 hours=1、关键字调用 hours=2——类里的方法就是函数,规矩全通用

规范提醒:把一个对象的全部属性都在 __init__ 里声明齐(哪怕先给个 0 或 None)。技术上你可以事后从外面 ada.new_attr = 1 随手加属性,但那会让"这个对象有什么"变得没人说得清——模具的意义就没了。

让 print 说人话:__str__

直接打印对象,输出是一串"火星文":

Python

__str____init__ 一样是双下划线家族(魔法方法):你不直接喊它们,Python 在特定时机自动喊——造对象时喊 __init__,print 时喊 __str__。魔法方法还有一大家子,现阶段认识这两个就够;以后在别人的代码里看到 __xxx__,知道"这是给 Python 自动调用的钩子"即可。

完整体检:一个类的解剖图

Python

这就是你现阶段需要的全部零件:docstring、__init__ 声明齐属性(含容器和默认值)、若干动词方法(带检查、带默认参数)、__str__ 自我介绍。以后你读到的绝大多数类,骨架都长这样——零件多点少点而已。

✍️ 练习

练习 1:找茬修类

下面的类有两处 self 相关的错误(正是本课警告过的两个高频坑),修好让它跑通。

Python
💡 提示

错误一在 add 的参数表(少了谁?);错误二在 report 的 f-string 里(task 是属性还是局部变量?)。

✅ 参考答案
class Timer:
    def __init__(self, task):
        self.task = task
        self.minutes = 0

    def add(self, minutes):          # 方法第一个参数必须是 self
        self.minutes = self.minutes + minutes

    def report(self):
        return f"{self.task} 已计时 {self.minutes} 分钟"   # 属性要带 self.


t = Timer("写周报")
t.add(25)
print(t.report())

练习 2:客服工单类

客服主管丽丽要管工单。写一个 Ticket 类:属性 customer(客户名)、issue(问题描述)、status(默认 "待处理");方法 close() 把 status 改成 "已解决";加 __str__ 输出形如 [待处理] 老王:无法登录。造两张工单,关掉其中一张,分别打印。

Python
✅ 参考答案
class Ticket:
    def __init__(self, customer, issue, status="待处理"):
        self.customer = customer
        self.issue = issue
        self.status = status

    def close(self):
        self.status = "已解决"

    def __str__(self):
        return f"[{self.status}] {self.customer}:{self.issue}"


t1 = Ticket("老王", "无法登录")
t2 = Ticket("小陈", "重复扣款")
t1.close()
print(t1)
print(t2)

练习 3:对象进容器(挑战)

对象和列表/推导式可以随意组合。用上面的 Ticket 类(答案里的版本已就位):① 建一个含 4 张工单的列表 ② 关掉其中两张 ③ 用列表推导式筛出所有"待处理"工单并逐个打印。

Python
💡 提示

对象的属性照常能进 if:[t for t in tickets if t.status == "待处理"]。打印用 for 逐个 print(print 会自动走 __str__)。

✅ 参考答案
class Ticket:
    def __init__(self, customer, issue, status="待处理"):
        self.customer = customer
        self.issue = issue
        self.status = status

    def close(self):
        self.status = "已解决"

    def __str__(self):
        return f"[{self.status}] {self.customer}:{self.issue}"


tickets = [
    Ticket("老王", "无法登录"),
    Ticket("小陈", "重复扣款"),
    Ticket("丽丽", "页面报错"),
    Ticket("大壮", "忘记密码"),
]
tickets[0].close()
tickets[2].close()

pending = [t for t in tickets if t.status == "待处理"]
for t in pending:
    print(t)

"一列表的对象 + 推导式筛选"是真实项目的日常形态——上单元的容器功夫和本单元的类,就此合流。

📝 随堂测验

随堂测验0 / 5 题正确

1. __init__ 方法在什么时候执行?

2. ada.report() 调用时,方法定义里的 self 是谁?

3. 方法里写 self.count = self.count + 1 和直接写 count = count + 1 的区别是?

4. 定义方法时写 def add(minutes): 忘了 self,调用 t.add(25) 会怎样?

5. 给类写 __str__ 方法的作用是?

本课小结

  • class 类名:(首字母大写)定义模具;__init__(self, ...) 是出厂设置,造对象时自动执行
  • self = "我":说明书里的代词;对象.方法() 时 Python 自动把对象传给 self
  • 属性挂在 self 上(self.x = ...),方法能读能改;属性在 __init__ 里声明齐是规矩
  • 两大高频坑:方法忘写 self 参数(TypeError)、属性忘写 self. 前缀(NameError)
  • __str__ 让 print 说人话;双下划线方法 = Python 自动调用的钩子

下一课看继承:新模具怎么"站在旧模具的肩膀上"——以及为什么这个特性要克制着用

划选正文任意文字可高亮、批注或加入复习卡

讨论

载入中…