R

ReflexKR

Reflex 官方文档

名牌机场:Python 对象模型

·

课程概览

1

标签不是箱子:名字与对象

2

封口的箱子:可变与不可变

3

箱中箱:容器与复制

4

交出箱子的时候:函数与参数

5

区域与通行证:作用域

6

随身行李:闭包

7

箱子规格书:类与实例

8

机场标准流程:双下划线方法

9

规格书的规格书:继承与 MRO

10

安检口:属性访问的秘密

11

无主的箱子:内存与 GC

12

储物柜号码:哈希与相等,综合

名牌机场:Python 对象模型
第1课

时间 0:00–0:50

标签不是箱子:名字与对象

失物报告单

LOST-001

原以为是两个箱子

报告人

旅行社职员 朴主任

丢了什么

团体纪念品清单。在“复制”出来备用的清单里加了一块冰箱贴,结果原来的清单里也多了一块冰箱贴。

结案条件

用代码证明两份清单从一开始就是同一个箱子,并做出一份真正的备用清单。

天空岛国际机场 行李中心

上班第一天的早上,都美兰班长在传送带前递给你一沓标签。“在这个中心,第一句要背下来的话是:箱子只有一个,标签可以有很多个。”

第一份报告来自一位旅行社职员。对方把纪念品清单多做了一份备用,可写进备用清单的东西,原来的清单里也会出现。班长看了看代码,笑了:“两份清单?是两个标签吧。”

1-1. 挂标签的 =(9 分钟)

报告人的代码是这样的:

souvenirs = ["postcard", "keyring"]
backup = souvenirs
backup.append("magnet")
print(souvenirs)
# ['postcard', 'keyring', 'magnet']

backup = souvenirs 并不会复制列表。它是在挂着 souvenirs 标签的那个箱子上,再挂一个 backup 标签。箱子从一开始就只有一个,backup.append 把冰箱贴放进的,正是这唯一的箱子。

  • = 先计算右边,得到一个对象(箱子),再把左边的名字(标签)绑定到这个对象上。
  • 如果右边是一个已有的名字,就不会产生新对象。只是同一个对象身上多了一个名字。

在下面的标签板上逐行推进看看。左栏是名牌,右栏是箱子。到第 3 行之前,你得先预测结果才能继续。

标签板

步骤 1 / 0

下一行将执行: 0

正在准备实验台…

刚刚变化的

封口的箱子(不可变)

过了第 2 行,箱子仍然只有一个。看看两支箭头是不是指向同一个列表。

1-2. 箱子的三要素:身份、类型、值(8 分钟)

每个对象都有三样东西。

怎么查看放到机场里就是
身份(identity)id(obj)、a is b印在箱底的唯一编号
类型(type)type(obj)箱子的种类(拉杆箱、背包……)
值(value)用 == 比较里面装的东西
x = ["postcard"]
y = ["postcard"]
print(x == y, x is y)
# True False
print(id(x) == id(y), id(souvenirs) == id(backup))
# False True
  • x 和 y 是内容完全相同的两个不同的箱子。== 为 True,is 为 False。
  • souvenirs 和 backup 是同一个箱子,所以 id 也相同。
  • id 的数字本身没有意义。在 CPython 里它是内存地址,但每次运行都不一样。只在比较时使用它。
print(type(x), type(len))
# <class 'list'> <class 'builtin_function_or_method'>

小钉提示

→ is 问的是“是不是同一个箱子”,== 问的是“装的东西一不一样”。比较值的时候一律用 ==。is 只用来确认世上独一无二的对象,比如 x is None。

1-3. 一切都是箱子(6 分钟)

不只是数字和列表才是对象。函数、类、模块,也都是绑定在名字上的对象。

shout = print
shout("boarding")
# boarding
print(shout is print)
# True

def greet():
    return "hi"

print(type(greet), greet.__name__)
# <class 'function'> greet
alias = greet
del greet
print(alias())
# hi
  • def greet(): 创建一个函数对象,并把名字 greet 绑定上去,本质上也是一种赋值。
  • 即使用 del greet 摘掉了这个名字,alias 仍指向同一个函数对象,所以函数照样存在。
  • 类也是对象。type(int) 和 type(type) 都是 <class 'type'>。这个话题第 7 课再展开。

1-4. 移动标签与改动箱子(11 分钟)

对一个名字能做的事只有两种。

  1. 移动标签(重新绑定):a = ...。把名字重新绑定到另一个对象上。原来的箱子不受影响。
  2. 改动箱子(修改):a.append(...)、a[0] = ...。名字不动,箱子里的东西变了。所有指向这个箱子的名字都能看到变化。
a = [1, 2]
b = a
a = a + [3]
print(a, b, a is b)
# [1, 2, 3] [1, 2] False
a = [1, 2]
b = a
a.append(3)
print(a, b, a is b)
# [1, 2, 3] [1, 2, 3] True

a + [3] 会创建一个新列表,然后 a = 把标签 a 移到这个新列表上。b 还留在原来的箱子上。而 append 改动的是箱子本身,所以从 b 也能看到。在下面交替运行这两种写法,对比一下。

标签板

步骤 1 / 0

下一行将执行: 0

正在准备实验台…

刚刚变化的

封口的箱子(不可变)

在 a = a + [3] 中,第 3 行之后箭头 a 移到了新箱子上;在 a.append(3) 中,箭头不动,只有箱子里面变了。
  • 在列表的图里,格子中的 1、2 是小值,所以直接写成了值,没有画箭头。其实它们也是对象,列表里装的是指向这些对象的引用(第 3 课)。
  • a += [3] 属于哪一种?对列表来说是改动箱子。可对数字或字符串来说,它却变成了移动标签。这两副面孔是第 2 课的主题。

1-5. del 摘掉的是标签,不是箱子(6 分钟)

c = ["tag"]
d = c
del c
print(d)
# ['tag']
print(c)
# NameError: name 'c' is not defined

del c 只是去掉名字 c,并不会删除列表。d 还指着它,所以箱子还在。箱子真正消失,是在没有任何标签指向它的时候(第 11 课)。

交换两个名字的 p, q = q, p 也是移动标签。先用右边的 q, p 生成一个元组,再把左边的名字依次绑定到元组里的对象上。

p, q = "left", "right"
p, q = q, p
print(p, q)
# right left

结案(10 分钟)

下面是报告人的两份清单其实是同一个箱子的证据,以及做出真正备用清单的方法。

souvenirs = ["postcard", "keyring"]
backup = souvenirs
backup.append("magnet")
print(souvenirs is backup, id(souvenirs) == id(backup))
# True True

safe = list(souvenirs)     # 新做一个箱子,装进同样的东西
safe.append("mug")
print(souvenirs, safe, safe is souvenirs)
# ['postcard', 'keyring', 'magnet'] ['postcard', 'keyring', 'magnet', 'mug'] False

list(souvenirs) 会创建一个新列表。现在往 safe 里放马克杯,原来的清单也不会变。(这种复制只“新建一层”,这一点第 3 课再讲。)

快下班时,小钉指向 13 号传送带。有报告说,两个一个标签都没有的箱子一直在上面转。班长只说了句“没有标签的话,早该被清走了”,就关掉了屏幕。

结案报告 — LOST-001。清单从一开始就只有一份,只是挂了两个标签。用 is 和 id 确认,用 list() 做出新清单解决。

课后练习

  1. 依次执行 x = [0]、y = x、x = [1] 之后,y 是什么?先画图,再运行确认。
  2. 设 a = [1, 2],再创建 b = a[:] 和 c = a,预测 a is b、a is c、a == b 的结果。
  3. 给 print 起一个别名,然后执行 del print,会怎样?内置名字住在哪里,第 5 课会学到。

班长的工作手册

  • 变量不是盒子,而是名牌。= 把左边的名字绑定到右边的对象上。

  • 对象的三要素:身份(id、is)、类型(type)、值(==)。

  • is 看是不是同一个对象,== 看值是否相等。比较值一律用 ==。

  • 函数、类、模块也是对象。def 也是一种绑定名字的赋值。

  • 重新绑定(a = …)移动名字,修改(a.append …)改变对象。

  • del 只是摘掉名字;对象要等到没有任何名字指向它时才会消失。

← 上一课

课程概览

下一课 →

第2课 · 封口的箱子:可变与不可变

订阅新课时和新课程通知

本课程新增课时或推出后续课程时,我们会发邮件通知你。

收集项目:电子邮箱 · 用途:本课程的新课时和上线通知 · 保存期限:直到你要求删除。不会用于其他用途,也不会提供给他人。回复任意通知邮件,我们会立即删除。

问答

关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。

以纯文本显示,不支持链接和格式。

R

ReflexKR

动手学 Python 和 Reflex。所有示例均已在 Reflex 0.10.0 上实际运行验证。

ReflexKR 免费,没有横幅广告。如果对你有帮助,欢迎请我们喝杯咖啡。 ☕ 请我们喝杯咖啡

联盟链接与赞助说明
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex