如何在python中使变量不可变

时间:2011-04-01 08:53:40

标签: python list

我的python脚本:

N = 2  # 2*2 matrix

a = N * [0]
b = a

print(b)  # prints [0, 0]

for i in range(N):
    a[i] = N * [0]

for i in range(N):
    for j in range(N):
        a[i][j] = 0

print(a)  # prints [[0, 0], [0, 0]]

print(b)  # prints [[0, 0], [0, 0]]

为什么我的第二个print(b)会发生变化?如何使它不变?我希望我的b仍然包含[0, 0]

4 个答案:

答案 0 :(得分:23)

您对Python和变量赋值中的“对象”的理解存在缺陷。

在像C这样的语言中,当你定义一个变量(比如说int a)时,会为这个变量分配和保留一小块内存,a现在指的是这个区域。记忆。您可以查看此区域,更改它并发现a“现在具有”不同的值。像a = 2(或a = b其中b是另一个变量)这样的语句会获取右侧的值并将其写入为a保留的内存位置。现在您可以根据需要修改b,但a仍将保留原始值。这就是为什么你可以在C中做a++之类的事情,这意味着,“获取a所指的内容的价值,为其添加一个并将其写回同一位置”。

在Python中,当您说x = []时,会创建一个新的列表对象,并使x“指向”该列表。现在,您对x所做的任何更改都会影响此对象。假设您说y = x,您将获得对同一对象的另一个引用。正在更改y(或x) 将更改xy现在指向的对象。这是您使用B = A作业完成的操作。当您通过A访问此对象时,所有通过B完成的操作都会显示,因为它们都指向同一个对象。从这个意义上讲,Python中的所有变量都像C中的指针一样。您也可以理解为什么我们在Python中没有++运算符,因为修改内存位置的内容就像在C中一样没有意义。

到目前为止,其他人建议的解决方案是建议您使用与A指向的列表完全相同的内容创建一个新对象,并使B指向此副本。这样,如果您修改A(或A指向的内容),B(或B指向的内容)将保持不变。

然而,

这不会使B“不可变”(即不能在适当位置修改的对象)。但是,我认为你只是错误地使用了这个词并且意味着你不希望发生别名。

答案 1 :(得分:10)

在python中分配对象时,可以分配引用(类似于C中的指针)。

有几种方法可以避免这种情况,但恕我直言最常用的是使用副本:

import copy
B = copy.copy(A)

在某些情况下,您甚至可能想要使用deepcopy(),请查看documentation了解详细信息。

答案 2 :(得分:6)

问题是:

B=A

现在两者都指向同一个对象。

尝试:

B = [i for i in A]

现在B是一个包含A中所有元素的新列表。或者只是:

B = A[:]

答案 3 :(得分:0)

更改分配B的方式:

B = A

B = A[:]