Python的秘密生活:Memory中的雕像
Source: Dev.to
演示字符串的别名
午后的阳光穿透图书馆空气中舞动的尘埃。Timothy 在掌握了 Name Tag 概念后信心十足。他想向 Margaret 展示自己学到的东西。
“看这个,” Timothy 把笔记本电脑转向她说。“我会创建两个标签,
greeting_one和greeting_two。它们指向同一个字符串对象。然后我会修改其中一个,证明另一个也会随之改变。”
greeting_one = "Hello"
greeting_two = greeting_one
# Timothy 的计划:通过第二个标签修改对象。
greeting_two += " World"
print(f"greeting_two is: {greeting_two}")
print(f"greeting_one is: {greeting_one}")
Timothy 预期两个变量都会显示 "Hello World"。
greeting_two is: Hello World
greeting_one is: Hello
他再次运行代码,得到相同的结果。
“但你说它们是引用!你之前用列表演示过!”
Margaret 解释说,字符串的行为不同于可变容器。
理解字符串的不可变性
Margaret 用一座大理石雕像作比喻:
- 石头(不可变) – 字符串不能就地修改,就像石像一样。
- 白板(可变) – 列表可以在不创建新对象的情况下被修改。
她展示了过程:
- Python 看到标记为
"Hello"的原始石块。 - 操作
greeting_two += " World"无法在现有石块上雕刻" World"。 - Python 创建一个 新石块,其中包含
"Hello World",并放在新的内存位置。 greeting_two重新绑定到这个新块,而greeting_one仍然指向原来的"Hello"块。
因此,+= 操作后,这两个标签不再引用同一个对象。
检查对象 ID
Timothy 想要具体的证据来证明创建了新对象。
s = "Hello"
print(f"Start ID: {id(s)}")
s += " World"
print(f"End ID: {id(s)}")
典型输出:
Start ID: 2667049832100
End ID: 2667051284300
不同的 ID 证实了 新字符串对象 已被分配。
不可变 vs 可变 类型
| 类别 | 示例 | 特征 |
|---|---|---|
| 不可变(石头) | str, int, float, tuple | 不能就地改变。+=、upper()、切片等操作会创建 新对象(重新绑定)。共享引用是安全的。 |
| 可变(白板) | list, dict, set | 可以就地修改。操作会改变原始对象,因此共享引用会看到这些更改。 |
要点
- 字符串(以及其他不可变类型)永远不会被修改;任何“修改”都会产生一个 新对象。
- 列表和其他可变容器可以就地改变,所以别名会看到相同的更新。
- 了解哪些对象是不可变的、哪些是可变的,有助于在共享引用时避免意外的 bug。
下次,Margaret 和 Timothy 将探讨 “真相的秘密生活”——发现即使在 Python 中,空也会是 False。