第六章 对象引用、可变性和垃圾回收

第六章 对象引用、可变性和垃圾回收

引用与绑定

传统“变量是盒子”的比喻具有误导性,尤其在面向对象语言(如 Java、Python)中。更准确的模型是“变量是贴在对象上的标签(便利贴)”,变量名只是对对象的引用,而非容器。

# 展示变量不是一个盒子而是一个标签
a = [1, 2, 3]        # 创建列表对象,并将标签 'a' 贴到该对象上
b = a                # 将标签 'b' 也贴到同一个列表对象上
a.append(4)          # 通过标签 'a' 修改对象内容
print(b)             # 输出: [1, 2, 3, 4]

b = a 并未复制列表,而是让 ba 指向同一个对象。若按“盒子”模型,会误以为 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(身份不同)

一个对象的身份在其创建后永远不会改变;你可以将其视

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值