这里“外部对象是否会被改变,只取决于它是不是可变对象,和是否使用复合运算符无关”这个说法不太准确。
可以直接看同一个 list 的两个例子:
def f(x):
x = x + [3]
x = [1, 2]
f(x)
print(x)
# [1, 2]
list 明明是可变对象,但外部的 x 并没有变化。原因是 x + [3] 创建了一个新的列表,函数里的局部变量 x 只是改为指向这个新列表,并没有修改原来的列表。
再看:
def f(x):
x += [3]
x = [1, 2]
f(x)
print(x)
# [1, 2, 3]
这里外部的 x 就变了,因为对 list 来说,+= 会原地修改原来的列表。
另外:
def f(x):
x[0] = x[0] + 1
x = [1, 2]
f(x)
print(x)
# [2, 2]
这里虽然右边 x[0] + 1 生成了一个新的整数,但左边 x[0] = ... 修改的是原列表内部的元素,所以外部仍然能看到变化。
所以更准确的说法应该是:
对象是否可变,决定它能不能被原地修改;而外部是否会看到变化,取决于函数内部这次操作到底是在原地修改原对象,还是只是让局部变量重新指向了一个新对象。
因此,“是否使用 +=、-= 这类复合运算符”不能说完全无关。你原来的对比例子有一点问题:你比较的是对“列表元素”进行 += 和普通赋值,而不是直接对 list 对象本身进行比较。对于列表元素来说,两种写法最终都可能修改原列表中的那个位置,所以看起来差别不大。更合适的对比应该是直接比较:
x = x + [3]
和:
x += [3]
这样才能清楚体现“重新绑定局部变量”和“原地修改原对象”的区别。