第六章 对象引用、可变性和垃圾回收
引用与绑定
传统“变量是盒子”的比喻具有误导性,尤其在面向对象语言(如 Java、Python)中。更准确的模型是“变量是贴在对象上的标签(便利贴)”,变量名只是对对象的引用,而非容器。
# 展示变量不是一个盒子而是一个标签
a = [1, 2, 3] # 创建列表对象,并将标签 'a' 贴到该对象上
b = a # 将标签 'b' 也贴到同一个列表对象上
a.append(4) # 通过标签 'a' 修改对象内容
print(b) # 输出: [1, 2, 3, 4]
b = a 并未复制列表,而是让 b 和 a 指向同一个对象。若按“盒子”模型,会误以为 b 拥有独立副本,无法解释为何修改 a 会影响 b。“便利贴”模型清晰说明:两个标签贴在同一对象上,修改对象内容自然对所有标签可见。
赋值的本质是"绑定"。Python 的赋值语句 x = ... 的含义是将名称 x 绑定到右侧表达式所创建或引用的对象。对象必须先存在,才能被绑定。赋值语句右侧先求值,左侧再绑定。
class Gizmo:
def __init__(self):
print(f'Gizmo id: {
id(self)}')
x = Gizmo() # 成功创建实例,绑定到 x
# 输出: Gizmo id: 4301489152
# 尝试创建第二个实例并执行非法操作
try:
y = Gizmo() * 10
except TypeError as e:
pass # 捕获异常,避免程序中断
# 查看当前命名空间
print([name for name in dir() if not name.startswith('__')])
# 输出包含 'Gizmo' 和 'x',但不包含 'y'
Gizmo() 在 * 10 之前已执行,因此会打印 Gizmo id: ...,说明对象已创建。但由于 Gizmo 实例不支持 * 运算,右侧表达式求值失败,抛出 TypeError。变量 y 从未被绑定,因为赋值语句左侧的绑定操作在右侧求值失败后不会执行。这证明:对象创建发生在绑定之前,且绑定仅在右侧成功求值后才发生。
身份、相等性与别名
**身份(Identity)**是对象在内存中的唯一标识,创建后永不改变。可通过 id() 获取(CPython 中为内存地址),用 is 运算符比较。**相等性(Equality)**指的是对象的值是否相同,由 == 运算符判断,实际调用 __eq__() 方法。**别名(Aliasing)**指的是多个变量绑定到同一个对象。
# 引用同一个对象
charles = {
'name': 'Charles L. Dodgson', 'born': 1832}
# 未创建新对象,仅新增一个标签
lewis = charles # lewis 是 charles 的别名
print(lewis is charles) # True
print(id(charles), id(lewis)) # 输出相同 ID,如 (4300473992, 4300473992)
lewis['balance'] = 950 # 通过 lewis 修改对象
print(charles) # {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
# 值相等但身份不同
alex = {
'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
print(alex == charles) # True(值相等)
print(alex is not charles) # True(身份不同)
一个对象的身份在其创建后永远不会改变;你可以将其视

最低0.47元/天 解锁文章


被折叠的 条评论
为什么被折叠?



