Python永久赋值变量
我刚开始学习python,遇到了一些奇怪的事情 以下代码为变量测试指定x=1和y=2的坐标。test2变量为自己分配与test相同的值,然后将test2的[x]值更改为旧的[x]值减去1。这很好,但是,当最后一部分被执行时,它不仅从test2中的[x]值减去1,而且对test变量中的[x]值也是如此Python永久赋值变量,python,list,reference,Python,List,Reference,我刚开始学习python,遇到了一些奇怪的事情 以下代码为变量测试指定x=1和y=2的坐标。test2变量为自己分配与test相同的值,然后将test2的[x]值更改为旧的[x]值减去1。这很好,但是,当最后一部分被执行时,它不仅从test2中的[x]值减去1,而且对test变量中的[x]值也是如此 test = [1,2]; test2 = test; test2[1] = test2[1] - 1; 我发现执行以下操作效果很好,但我仍然不明白为什么第一个方法会更改test值以及test2值
test = [1,2];
test2 = test;
test2[1] = test2[1] - 1;
我发现执行以下操作效果很好,但我仍然不明白为什么第一个方法会更改test值以及test2值
test = [1,2];
test2 = test;
test2 = [test2[0] -1 ,test2[1]];
有人能解释一下为什么会这样吗
多谢各位
这是因为当您执行
test2=test
时,您没有复制列表的内容,而是简单地将test2
的引用分配给原始列表。因此,对test2
的任何更改也将影响test
正确的方法是使用“复制”模块(或copy()
,如果可以轻松复制的话)
import copy
test2 = copy.deepcopy(test) # deep copy
test2 = copy.copy(test)) # shallow copy
test2 = test[:] # shallow copy using slices
有关更深入的说明以及复制列表的其他方法,请参阅。
[1,2]
是一个数组,当您将其分配给test
时,您会将一个引用分配给该数组进行测试。因此,当您执行test2=test
时,您会将引用分配给另一个变量。对任何变量进行更改,数组都会更改
您的第二个示例是有效的,因为您创建了一个新的数组。您也可以这样做:
test = [1,2]
test2 = [test[0]-1, test[1]]
Python不执行赋值 它没有名称绑定 这是一个不同之处,它被解释得精彩而详细 在您的第一个示例中: 第一行将名称“test”绑定到由“[1,2]”表达式创建的列表对象。 第二行将名称“test2”绑定到绑定到“test”的同一个对象。 第三行修改绑定到“test2”的对象,该对象与绑定到“test”的对象相同 在第二个示例中: 第一行将名称“test”绑定到由“[1,2]”表达式创建的列表对象。 第二行将名称“test2”绑定到绑定到“test”的同一个对象。 第三行将名称“test2”绑定到由表达式“[test2[0]-1,test2]”创建的新对象 如果您确实希望两个具有相同值的独立列表绑定到不同的变量,则需要:
>>> test = [1, 2]
>>> test2 = list(test)
>>> test2[0] = 3
>>> print(test)
[1, 2]
>>> print(test2)
[3, 2]
请注意,这是一个浅拷贝列表,因此如果在该列表中找到相同的对象,那么在test2
中更改元素的对象状态当然会影响test
p、 在Python中,就像在Java中一样,赋值本身从不进行复制——rahter,赋值将另一个引用添加到与=
右侧相同的对象(参数传递的方式相同).奇怪的是,你从来没有听说过这个概念,当时Python非常流行,Java甚至更流行(许多其他语言的工作方式也很相似,可能更复杂或更独特)
在Python中,根据您的具体用途,有几种方法——标准库的copy
模块是一种流行的方法(函数copy
,表示“浅层”拷贝,以及deepcopy
——当然,对于“深度”拷贝,也就是说,不仅是容器,而且每个包含的项目都会递归地进行深度拷贝)
然而,通常情况下,你想要的是“一个新列表”——不管原始序列是列表、副本还是其他可编辑的东西,你可能不在乎:你想要一个新的
列表
实例,其项目与“其他东西”的项目相同。表达这一点的最佳方式是使用列表(somethingelse)
--调用列表
类型,该类型始终生成列表的新实例,并将您想要在新列表中显示其项的iterable作为参数。类似地,dict(somemapping)
生成新的dict
,以及set(someiterable)
创建一个新的集合——调用一个类型来创建该类型的新实例是一个非常通用和有用的概念!嗨,艾琳,谢谢你的回答。这是我第一次在任何语言中看到这一点。有没有办法只复制内容而不以任何方式链接它们?谢谢TheLorax@The_Lorax事实上,许多语言都表现为就是这样。最明显的一个总是使用副本的是PHP。对于这种示例,test2=test[:]就足够了。但是对于列表中的列表或其他讨厌的结构,deepcopy是最好的选择。这个test2[1]=test2[1]-1;
与您的描述不匹配。test2[1]
是数组的y值;x值应该是test2[0]
。专业提示:在Python中,分号是不必要的,通常省略它们。:)但是:a=5
,b=a
,a=6
,断言(b==6)
-断言失败?这不是一个参考;对我来说似乎是一个副本?再次,这是由于名称绑定而不是赋值语义。当你说“b=a”时,你将名字“b”绑定到绑定到“a”的对象上,即5。然后,当您说“a=6”时,您正在(重新)将名称“a”绑定到对象“6”,但名称“b”仍然绑定到“5”。赋值是名称绑定的一种形式(其他名称绑定语句包括def
,class
,import
,表单
,with
和除了withwithas
子句,…)。重新绑定一个barename(即,绑定一个以前绑定到其他名称的barename)不会影响该名称以前绑定到的任何对象(也不会影响什么是或不绑定到其他名称)。