我在做一个小程序,需要生成一个随机数列表,然后将之赋值给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
关于这个问题,我还没有研究明白,还没搞懂到底哪些变量是这样传值的,算是一个小小的坑吧。
参考资料:
- http://stackoverflow.com/questions/8744113/python-list-by-value-not-by-reference
- https://docs.python.org/3/faq/programming.html#how-do-i-copy-an-object-in-python