我的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]
。
答案 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
)
将更改x
和y
现在指向的对象。这是您使用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[:]