Python 永久赋值变量
我刚开始学Python,遇到了一些奇怪的事情。
下面的代码给变量test赋值,x=1,y=2。然后变量test2把自己设置成和test一样的值,接着把test2的[x]值改成原来的[x]值减去1。这一切看起来都没问题,但在执行最后一部分时,不仅test2的[x]值减了1,test的[x]值也跟着减了1。
test = [1,2];
test2 = test;
test2[1] = test2[1] - 1;
我发现这样做是可以的,但我还是不明白为什么第一种方法会同时改变test和test2的值。
test = [1,2];
test2 = test;
test2 = [test2[0] -1 ,test2[1]];
有人能解释一下为什么会这样吗?
谢谢你们,TheLorax
4 个回答
[1,2]
是一个数组,当你把它赋值给 test
时,其实是把这个数组的“地址”赋给了 test。也就是说,test
只是指向这个数组的一个标签。当你执行 test2=test
时,你又把这个“地址”赋给了另一个变量 test2。这样一来,修改任何一个变量,数组的内容都会跟着改变。
你的第二个例子之所以能工作,是因为你创建了一个全新的数组。你也可以这样做:
test = [1,2]
test2 = [test[0]-1, test[1]]
这是因为当你执行 test2 = test
时,你并不是在复制列表的内容,而只是给 test2
赋了一个指向原始列表的引用。所以,对 test2
的任何修改也会影响到 test
。
正确的做法是使用 deepcopy()
,这是来自复制模块的一个函数(如果你只需要简单的复制,可以使用 copy()
)。
import copy
test2 = copy.deepcopy(test) # deep copy
test2 = copy.copy(test)) # shallow copy
test2 = test[:] # shallow copy using slices
想了解更多详细信息和其他复制列表的方法,可以查看 这个页面。
在Python中,就像在Java里一样,赋值本身并不会复制对象——赋值只是给右边的对象添加了一个新的引用。这就像传递参数的方式也是一样的。你可能会觉得奇怪,为什么你从来没听说过这个概念,毕竟Python很流行,而Java更是如此(还有很多其他语言也差不多,只是可能会更复杂或者有些不同)。
当你想要一个复制品时,你需要请求一个复制品(这可以在右边的表达式中进行,或者在传递参数时使用)!在Python中,根据你的具体需求,有几种方法可以做到——标准库中的copy
模块就是一个常用的方法(里面有copy
函数,用于“浅复制”,还有deepcopy
函数,用于“深复制”,也就是说,不仅仅是容器本身,里面的每一个元素也会递归地深复制)。
不过,很多时候你想要的只是“一个新的列表”——无论原来的序列是列表、复制品,还是其他可迭代的东西,你可能并不在乎:你只想要一个新的list
实例,里面的元素和“其他东西”是一样的。最简单的方式就是使用list(somethingelse)
——调用list
类型,这样总是会创建一个新的列表实例,并把你想要的可迭代对象作为参数传进去。类似地,dict(somemapping)
会创建一个新的dict
,而set(someiterable)
会创建一个新的集合——调用一个类型来创建该类型的新实例是一个非常通用且有用的概念!