我认为我已经解决了我自己的问题,但我正在寻求更好地理解为什么,或者开悟/直接设置。
我有一个名单,我称之为vec:
vec = [0.0, 0.0]
在读入数据时更改值。
为了比较当前值和之前的值,我有另一个列表,我称之为oldvec。 如果我将oldvec定义为
oldvec = vec
然后每次vec改变值时它都会改变值,所以比较是没用的 - 它们总是相同的。
然而,如果我改为写
oldvec = [vv for vv in vec]
我没有这个问题 - oldvec即使在vec改变时也保持其值,因此当前和之前的向量之间的比较按照我需要的方式工作,即它实际上检测重复和非重复! ......为什么?
答案 0 :(得分:1)
将oldvec设置为vec字面意思使oldvec指向vec。您尚未创建新列表,您只需为其创建另一个名称。通过使用列表推导,您将显式创建列表的新副本,相当于vec.copy()。
答案 1 :(得分:1)
您可以通过id
函数了解其中的一个方法。这将显示对象的内存地址。内存地址是指对象存储在物理内存中的位置。
如果我们为这三个命令运行它,并查看不同的地址(这只是在我的计算机上;如果你自己运行它,你会得到不同的数字):
>>> vec = [0.0, 0.0]
>>> print id(vec)
4501729936
>>> oldvec1 = vec
>>> print id(oldvec1)
4501729936
>>> oldvec2 = [vv for vv in vec]
>>> print id(oldvec2)
4502046984
我们看到vec
和oldvec1
引用相同的地址,因此它们是同一对象的两个不同标签。在幕后,Python正在操作地址4501729936
处的对象:变量名称vec
和oldvec1
只是我们使用的方便标签。它们不是指“不同”的对象。
相比之下,oldvec2
完全不同。当Python运行列表推导时,它不知道这会产生与以前相同的列表,因此它会创建该列表的新副本。
这是一个快速的'肮脏的图片,以显示正在发生的事情。虽然红色blob和绿色博客恰好包含相同的信息,但它们是两个不同的blob。 vec
和oldvec1
都指向相同的红色斑点,因此任何一个上的任何操作都会影响底层的红色斑点,并反映在另一个中。相比之下,oldvec2
指向一个完全不同的绿色斑点,它恰好是红色斑点中的信息副本,但绿色斑点的变化不会影响红色斑点。
答案 2 :(得分:0)
在Python中,变量是"引用"意思是你可以有两个引用同一个对象的变量。在您的第一个示例中,发生了什么:同一列表中的两个名称。
如果您需要第二个实际列表,您可以"复制"第一个。有关方法,请参阅此处:How to clone or copy a list?
请注意,这也适用于列表中的项目 - 如果它们是更复杂的对象,您可以选择执行"深层复制"列表,复制每个元素的每个部分,或复制简单的复制",只复制引用,因此您有一个包含对原始对象的新引用的新列表。您需要为每个用例选择正确的方法。
答案 3 :(得分:0)
你应该把Python列表视为一个对象:在内存中的某个地方实例化的东西,有一个或多个指针存储它的内存地址 - 也就是说,当你说[]
时,你正在某个地方分配一些新的空间。记忆。因此,当您致电vec = [0.0, 0.0]
时,它会在内存中的某处创建一个新列表,它的地址会存储在vec
变量中。因此,当您执行oldvec = vec
时,您只需将地址从vec
复制到oldvec
。
让我举一个例子说明:例如,假设您的列表[0.0, 0.0]
存储在地址0x0800
。当您说vec = [0.0, 0.0]
时,vec
变量现在收到0x0800
。当您说oldvec = vec
时,oldvec
会收到相同的0x0800
。因此,当您访问oldvec
的第一个元素时,您确实正在访问vec
指向的相同列表。
现在,想想你的新专栏:oldvec = [vv for vv in vec]
。当你执行[]
时,它会在内存中的其他位置创建一个新列表,对吧?正如vec
命令所示,此列表中填充了for
的元素。因此,它会在内存中的其他位置创建一个新列表,存储0.0
和0.0
(如果我正确理解您所解释的内容,则会存储新元素)。这就是Python内部处理命令的方式。
希望有所帮助。