填充列表 - python在做什么?

时间:2014-10-05 04:29:00

标签: python list

我认为我已经解决了我自己的问题,但我正在寻求更好地理解为什么,或者开悟/直接设置。

我有一个名单,我称之为vec:

vec = [0.0, 0.0] 

在读入数据时更改值。

为了比较当前值和之前的值,我有另一个列表,我称之为oldvec。 如果我将oldvec定义为

oldvec = vec

然后每次vec改变值时它都会改变值,所以比较是没用的 - 它们总是相同的。

然而,如果我改为写

oldvec = [vv for vv in vec] 

我没有这个问题 - oldvec即使在vec改变时也保持其值,因此当前和之前的向量之间的比较按照我需要的方式工作,即它实际上检测重复和非重复! ......为什么?

4 个答案:

答案 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

我们看到vecoldvec1引用相同的地址,因此它们是同一对象的两个不同标签。在幕后,Python正在操作地址4501729936处的对象:变量名称vecoldvec1只是我们使用的方便标签。它们不是指“不同”的对象。

相比之下,oldvec2完全不同。当Python运行列表推导时,它不知道这会产生与以前相同的列表,因此它会创建该列表的新副本。


这是一个快速的'肮脏的图片,以显示正在发生的事情。虽然红色blob和绿色博客恰好包含相同的信息,但它们是两个不同的blob。 vecoldvec1都指向相同的红色斑点,因此任何一个上的任何操作都会影响底层的红色斑点,并反映在另一个中。相比之下,oldvec2指向一个完全不同的绿色斑点,它恰好是红色斑点中的信息副本,但绿色斑点的变化不会影响红色斑点。

enter image description here

答案 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.00.0(如果我正确理解您所解释的内容,则会存储新元素)。这就是Python内部处理命令的方式。

希望有所帮助。