Python中i += x与i = i + x是否等价:深入解析可变与不可变对象

Owen
Owen
发布时间:2026-10-13 | 3人浏览过
原创

本文深入解析Python中i += x与i = i + x的等价性问题。通过对比整数与列表的操作结果,揭示两者在调用__iadd__与__add__方法时的本质差异。重点阐述可变对象与不可变对象的内存行为,指出对列表使用+=可能引发的潜在Bug,帮助开发者避免常见的引用错误。

前言

近期遇到一个看似简单却蕴含深意的Python题目:表达式 i += x 与 i = i + x 是否等价?若回答“是”,则仅得50分。为何只算对一半?在常规认知中,二者看似无异,特别是在处理整数时表现一致。然而,当涉及列表操作时,情况是否依然如此?

首先观察以下两段代码示例:

代码1

>>> l1 = range(3)
>>> l2 = l1
>>> l2 += [3]
>>> l1
[0, 1, 2, 3]
>>> l2
[0, 1, 2, 3]

代码2

>>> l1 = range(3)
>>> l2 = l1
>>> l2 = l2 + [3]
>>> l1
[0, 1, 2]
>>> l2
[0, 1, 2, 3]

对比代码1与代码2,l2的最终值相同,但l1的值却存在差异。这表明 i += x 与 i = i + x 并非完全等价。那么,究竟在何种条件下等价,何种情况下不等价?

要厘清这一问题,首先需理解两个核心概念:可变对象与不可变对象。

在Python中,所有对象均具备三个通用属性:唯一标识、类型和值。

唯一标识:用于标识对象在内存中的唯一性,该标识在对象创建后保持不变,可通过函数 id() 查看。

类型:决定对象支持的操作,不同类型对象支持的操作各异,例如列表拥有 length 属性而整数没有。对象类型一旦确定便不再改变,可通过函数 type() 获取类型信息。

对象的值与唯一标识不同,并非所有对象的值都固定不变。某些对象可通过特定操作改变其值,这类对象称为可变对象(mutable);反之,值无法改变的对象称为不可变对象(immutable)。

不可变对象(immutable)

对于不可变对象,其值自创建起便恒定不变。对该对象执行的任何操作都会生成一个新的对象。

>>> a = 1
>>> id(a)
32574568
>>> a += 1
>>> id(a)
32574544

整数 “1” 是不可变对象。初始赋值时,变量 a 指向整数对象 1。执行 += 操作后,a 指向新的整数对象 2,而原对象 1 保持不变。常见的不可变对象包括:int、tuple、set、str。


可变对象(mutable)

可变对象的值可通过特定操作动态改变,例如列表对象可通过 append 方法不断添加元素,其值随之变化。当一个可变对象被赋值给两个变量时,它们共享同一实例,指向相同的内存地址。对任一变量进行操作,均会影响另一变量。

>>> x = range(3)
>>> y = x

>>> id(x)
139726103041232
>>> id(y)
139726103041232

>>> x.append(3)
>>> x
[0, 1, 2, 3]
>>> y
[0, 1, 2, 3]

>>> id(x)
139726103041232
>>> id(y)
139726103041232

执行 append 操作后,对象的内存地址不变,x 和 y 仍指向原对象,仅其值发生变化。


理解可变与不可变对象后,回归问题本身:+= 与 + 的区别何在?

+= 操作首先尝试调用对象的 __iadd__ 方法;若不存在该方法,则尝试调用 __add__ 方法。接下来分析这两个方法的区别。

__add__ 和 __iadd__ 的区别

  1. __add__ 方法接收两个参数,返回它们的和,且两个参数的值均不改变。
  2. __iadd__ 方法同样接收两个参数,但属于原地操作(in-place),即它会改变第一个参数的值。因此,该操作要求对象必须是可变的,不可变对象不具备 __iadd__ 方法。
>>> hasattr(int, '__iadd__')
False
>>> hasattr(list, '__iadd__')
True

显然,整数对象没有 __iadd__ 方法,而列表对象提供了该方法。

>>> l2 += [3] # 代码1:使用__iadd__,l2的值原地修改

代码1中的 += 操作调用的是 __iadd__ 方法,它会原地修改 l2 所指对象的值。

>>> l2 = l2 + [3] # 代码2:调用 __add__,创建了一个新的列表,赋值给了l2

而代码2中的 + 操作调用的是 __add__ 方法,该方法返回一个新对象,原对象保持不变。此时 l1 仍指向原对象,而 l2 指向新对象。

以上即为表达式 i += x 与 i = i + x 的区别。因此,对列表进行 += 操作时可能存在潜在 Bug,因为 l1 会随 l2 的变化而改变,正如函数参数不宜使用可变对象作为默认值一样。

总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表