系列 · Python 零基础到简单脚本 第 10 篇 / 共 11 篇 教程

Python 类与对象(选修):看见实例怎样保存独立状态

选修章节:用 Product 商品库存图解 class、实例、__init__、self、属性和方法,并判断什么时候字典加函数已经足够。

作者:黄撑 更新于 2026-08-27
本文目录 6 节 · 点击展开

本章是选修。 完成前面的变量、容器、判断、循环、函数、文件和异常后,你已经能写完整的数据处理脚本;不学习类,也不影响完成 Python 入门主线。

类适合解决一种更具体的问题:脚本里反复出现同一类对象,每个对象需要长期保存自己的状态,并且有多项行为总在操作这些状态。若只是读取 JSON、筛选订单、计算一次金额,字典加函数通常更直接。

先决定:字典加函数已经够用吗

一个商品只有 SKU、库存和补货判断时,下面的写法完全正确:

product = {
    "sku": "K161",
    "stock": 3,
}


def need_restock(product):
    return product["stock"] < 5


def add_stock(product, quantity):
    product["stock"] += quantity


print(need_restock(product))
add_stock(product, 5)
print(product["stock"])

数据保存在字典里,函数从外部接收字典并操作它。对于几十行的临时脚本,这种关系一眼就能看懂。

同一任务 · 两种组织方式类不是升级版语法,只是另一种职责边界
字典 + 函数数据和操作分开放
数据product = {“sku”: …, “stock”: …}
操作need_restock(product)add_stock(product, 5)
更适合
数据来自 JSON,结构临时,操作数量少
优点
代码直接,和外部数据形状接近
信号
函数显式接收要处理的字典
类 + 实例状态和相关行为放在一起
定义class Product
实例product = Product(“K161”, 3)product.add_stock(5)
更适合
同类对象反复出现,并长期保留各自状态
优点
和状态紧密相关的多项行为有固定入口
信号
通过当前实例调用自己的方法

判断标准:状态和行为需要长期一起存在,类才开始自然;只是为了让代码“看起来正式”,不要增加类。

用一个完整 Product 类贯穿本章

下面是本章唯一的主类。代码可以直接复制运行:

class Product:
    def __init__(self, sku, stock):
        self.sku = sku
        self.stock = stock

    def need_restock(self):
        return self.stock < 5

    def add_stock(self, quantity):
        self.stock = self.stock + quantity


product1 = Product("K161", 3)
product2 = Product("K162", 10)

print(product1.sku, product1.stock, product1.need_restock())
print(product2.sku, product2.stock, product2.need_restock())

product1.add_stock(5)

print(product1.sku, product1.stock, product1.need_restock())
print(product2.sku, product2.stock, product2.need_restock())

输出:

K161 3 True
K162 10 False
K161 8 False
K162 10 False

这段程序只需要先认识五个词:

本例作用
Product定义这一类对象保存什么数据、能做什么
实例 / 对象product1product2根据类创建出来的两个具体商品
属性self.skuself.stock当前实例自己保存的数据
方法need_restock()add_stock()当前实例可以执行的行为
self正在初始化或调用方法的那个实例让方法找到“这一个对象”的属性

Product("K161", 3) 怎样变成一个实例

调用类时,Python 先准备一个新的 Product 实例,再调用 __init__ 写入初始状态。__init__ 的职责是初始化,不是把实例 return 出来。

调用类 → 准备实例 → init → 写入属性 → 绑定名字Product("K161", 3) 的初始化轨迹
  1. 01 · 调用位置product1 = Product(“K161”, 3)

    请求创建一个新的 Product 实例。

  2. 02 · 新实例self → 新的 Product 对象

    Python 准备空实例,并把它作为 self 交给初始化方法。

  3. 03 · 参数进入sku → “K161”stock → 3

    调用中的两个实参进入 init 的参数名。

  4. 04 · 写入属性self.sku = skuself.stock = stock

    右边读取参数值,左边把值保存到当前实例。

  5. 05 · 实例完成product1 → Product 实例sku: “K161” · stock: 3

    初始化结束,调用表达式得到实例并绑定给 product1。

最容易混淆的是:

self.stock = stock
  • 右边的 stock 是这次调用传进 __init__ 的参数,当前值为 3
  • 左边的 self.stock 是新实例自己的属性,以后可以通过 product1.stock 读取。

调用 Product("K161", 3) 时,不需要手工传 self。Python 自动让 self 指向当前正在初始化的新实例。

两个实例为什么能保存独立状态

再次调用 Product("K162", 10) 时,Python 会准备另一个新实例。两个对象都按照 Product 的定义拥有 skustock,但属性值各自保存在自己的实例中。

现在只调用:

product1.add_stock(5)

调用方法时,Python 自动让 self 指向点号左边的 product1,并让参数 quantity 得到 5

之前 → 当前方法 → 之后product1 改变,product2 没有参与这次调用
01 · 调用之前
product1K161stock = 3
product2K162stock = 10

两个名字指向两个不同实例,各自拥有 stock 属性。

02 · 当前方法product1.add_stock(5)
self
→ product1
quantity
→ 5
self.stock = self.stock + quantity

代入当前对象:3 + 5 → 8

03 · 调用之后
product1K161stock: 3 → 8
product2K162stock: 10 → 10 · 未改变

方法只通过 self 修改 product1,没有访问 product2。

方法可以读取当前实例的属性:

def need_restock(self):
    return self.stock < 5

product1.need_restock() 中的 self.stock 读取 product1 当前的库存;product2.need_restock() 则读取 product2 的库存。调用者不传 self,但需要通过具体实例调用方法。

什么时候应该停留在字典和函数

继续使用字典和函数,通常更适合:

  • 数据直接来自 JSON,只需读取、筛选、转换后写出。
  • 脚本很短,数据只是一次性中间结果。
  • 只有一两个简单操作,函数参数已经清楚。
  • 类只会包住一个乘法或一条判断,没有长期状态。

可以考虑类的信号是:

  • 同一种实体会创建很多个实例。
  • 每个实例需要在程序运行期间持续保存、改变自己的状态。
  • 多个方法都围绕同一组属性工作。
  • product.add_stock(5) 这种调用比反复传字典更符合业务阅读方式。

不要为了一个乘法创建 AmountCalculator,也不要把每个字典都机械转换成对象。类增加了定义、初始化和方法调用三层结构,只有它们换来了更清楚的状态边界才值得。

动手练习:沿着 self 追踪状态

复制完整 Product 程序,先预测再运行:

  1. 创建 product3 = Product("K163", 0),写出调用 __init__selfskustock 分别指向什么。
  2. 调用 product3.add_stock(2),写出属性变化前后的值。
  3. 确认 product1 和 product2 的库存没有被 product3 的方法调用改变。
  4. 给 Product 增加 remove_stock(quantity),只修改当前实例的库存。
  5. 回到最开始的字典版本:如果脚本只执行一次补货判断,你会选哪种写法?说明理由。