Python中的变量复制是如何工作的?

4
为什么会出现这种情况:
 >>> a = 1
 >>> b = a
 >>> a = 2
 >>> print(a)
 2
 >>> print(b)
 1

...但是:

 >>> a = [3, 2, 1]
 >>> b = a
 >>> a.sort()
 >>> print(b)
 [1, 2, 3]

我的意思是,为什么变量会被复制而迭代器只是被引用呢?

1
在我看来,学习Python最困难的部分之一就是学会区分何时你正在获取现有对象并修改它以及何时你正在获取现有名称并使其指向不同的对象 - turbulencetoo
@turbulencetoo:很简单。这些示例都没有在此处复制对象。对象可能有多个名称。名称可能在不同的时间指向不同的对象。这张图片可能会提供一些见解 - jfs
3个回答

7
变量并没有"真正复制"。变量是对象的名称,而赋值运算符将名称绑定到运算符右侧的对象。更详细地说: >>> a = 1 的意思是 "将a设置为指向对象1"。 >>> b = a 的意思是 "将b设置为指向与a指向的相同的对象,也就是1"。 >>> a = 2 的意思是 "将a设置为指向对象2"。这不会对任何其他引用指向的对象产生影响,比如b引用的对象1
在你的第二个示例中,ab都是指向同一个列表对象的名称。a.sort()直接在原处修改了该对象,因为两个变量都指向同一个对象,所以修改的效果可在两个名称下观察到。

请参阅以下问题的更长且更详细的讨论:https://dev59.com/LXNA5IYBdhLWcg3wYMt-和https://dev59.com/3nRB5IYBdhLWcg3wuZbo。 - Peter DeGlopper
我认为简要解释可变性以及为什么当b和a是整数时a+=1不会改变b,但如果a和b都是列表,则a+=[1]会改变b,这也值得一提。 - R Nar

2

将指定的变量视为指向存储值的内存位置的指针。您可以使用id实际获取内存位置。

a = 1
b = a

>>> id(a)
4298171608

>>> id(b)
4298171608  # points to the same memory location

a = 2
>>> id(a)
4298171584  # memory location has changed

以列表为例,你可以看到两个变量指向同一内存地址的同一个对象。

在实际操作中,它们都是对同一对象进行操作,只不过使用了不同的变量。
a = [3, 2, 1]
b = a
a.sort()

>>> id(a)
4774033312

>>> id(b)
4774033312  # Same object

1
请注意,返回内存位置的 id 是一种实现细节 - 对于常见的 C Python 实现是正确的,但并不保证在所有实现中都是正确的。如果两个对象的 id 相同,则这两个对象相同是可靠的。对于像整数和字符串这样的不可变对象,id 的含义是一个更复杂的问题 - 通常你永远不需要关心它们,因为它们是不可变的。 - Peter DeGlopper

0

在你的第一个例子中,在将b的值设为a之后,你重新分配了a的值。因此,a和b携带不同的值。

如果你在第二个例子中将a重新分配为一个新的排序列表而不是就地排序,那么也会发生同样的情况。

a = [3,2,1]
b = a
a.sort()
print b
[1,2,3]

但是...

a = [3,2,1]
b = a
sorted(a)
print b
[3,2,1]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接