Python 中 list 的传值问题

我在做一个小程序,需要生成一个随机数列表,然后将之赋值给2个 list,并需要这两个列表完全独立(即列表值指向不同的内存地址)。最开始是这样的:

>>> a = [5,4,3,2,1]
>>> b = a
>>> print(a,'-',id(a)) # id是 python 查看对象地址的方法
[5, 4, 3, 2, 1] - 4516275720
>>> print(b,'-',id(b))
[5, 4, 3, 2, 1] - 4516275720 # 显然,此时a和b指向同一个地址
>>> b.sort() # sort()是 python 的内置排序函数
>>> print(b,'-',id(b))
[1, 2, 3, 4, 5] - 4516275720
>>> print(a,'-',id(a))
[1, 2, 3, 4, 5] - 4516275720 # 我去,怎么回事???a 怎么也变了?

Python 的变量赋值机制并不是真的给变量赋值(实际上从头到尾都不存在 list 的容器),只是把变量名当做一个标签,贴在内存地址上,当值发生变化的时候,并不是改变值本身,而是将内存地址对应的标签『唰』的一下撕下来,然后贴到另一个地址上——此所谓『铁打的内存,流水的变量名』。
对于复制 list,按照官方文档的说法,应该这样操作:

b = a[:]
# https://docs.python.org/3/faq/programming.html#how-do-i-copy-an-object-in-python

此时是这样的:

>>> a = [5,4,3,2,1]
>>> b = a[:]
>>> print(a,'-',id(a))
[5, 4, 3, 2, 1] - 4516276488
>>> print(b,'-',id(b))
[5, 4, 3, 2, 1] - 4516276232

可见在 b = a[:] 这一过程中,Python 在内存中创建了一个新值,并将 b 的标签贴到了上面,迥异于我们最开始的过程。
其实上述过程并非发生在所有数据类型中。

>>> A = 5
>>> B = A
>>> id(A)
4540535120
>>> id(B)
4540535120
>>> B = 3
>>> A
5
>>> id(A)
4540535120
>>> id(B)
4540535056

关于这个问题,我还没有研究明白,还没搞懂到底哪些变量是这样传值的,算是一个小小的坑吧。
参考资料:

  1. http://stackoverflow.com/questions/8744113/python-list-by-value-not-by-reference
  2. https://docs.python.org/3/faq/programming.html#how-do-i-copy-an-object-in-python
Tagged : /