我有点困惑,为什么在恢复后两个输出都会发生变化,而它肯定应该只有一个(输出在注释中说明)。当然只有第一个应该改变吗?如果有人能给我一个关于为什么会发生这种情况的建议,我会很感激
def switcher(y):
# shifts two characters
temp = y[0]
y[0] = y[1]
y[1] = temp
sub = [[1,2,3],[1,2,3]]
switcher(sub[0])
sub
#[[2, 1, 3], [1, 2, 3]]
#restore
sub[0] = sub[1]
sub
# [[1, 2, 3], [1, 2, 3]]
switcher(sub[0])
sub
#[[2, 1, 3], [2, 1, 3]]
使用sub[0] = sub[1]
,您将两个列表定义为同一对象,这就是为什么后续更改将应用于这两个列表。例如,执行sub[0] = sub[1][:]
以创建副本(对于列表,有更多的方法可以这样做)。
在执行sub[0] = sub[1]
时,将对索引1
处的值的引用(即,在您的情况下为[1, 2, 3]
)分配给索引0,因此最终两个列表都位于同一内存位置,其中一个的更改会对另一个进行相应的更改。
您可以使用id
内建函数来验证这一点,该函数表示给定值的内存引用:
初始化后的ids:
>>> sub = [[1,2,3],[1,2,3]]
>>> [id(s) for s in sub]
[1385461417096, 1385461338824]
调用交换机后的ids:
>>> switcher(sub[0])
>>> [id(s) for s in sub]
[1385461417096, 1385461338824]
分配sub[0] = sub[1]
:后的id
>>> sub[0] = sub[1]
>>> [id(s) for s in sub]
[1385461338824, 1385461338824]
正如你所看到的,在分配sub[0] = sub[1]
之后,id是相同的,当修改其中一个子列表时,两个子列表都会发生变化
有问题的行是分配
sub[0] = sub[1]
分配从不复制数据。
您告诉Python,引用sub[0]
和sub[1]
现在都指向内存中的同一列表对象(内容为[1,2,3]
)。
在您的特定情况下,通过在作业右侧复制一份(浅)列表,可以很容易地解决此问题。
sub[0] = sub[1][:]
引用有问题。通过定义:
sub = [[1,2,3],[1,2,3]]
你创建了一个由两个不同列表组成的列表,但当你这样做时:
sub[0] = sub[1]
您正在告诉python将sub[1]复制到sub[0]中,因此对于python,您的新矢量将是:
sub <- [ reference_to_memory_where_sub1_is, sub1 ]
为了避免这种行为,您可以明确地告诉python在内存中复制对象。您可以使用模块";复制":
import copy
def switcher(y):
# shifts two characters
temp = y[0]
y[0] = y[1]
y[1] = temp
l1 = [1,2,3]
l2 = [1,2,3]
sub = [copy.deepcopy(l1),copy.deepcopy(l2)]
switcher(sub[0])
print(sub)
#[[2, 1, 3], [1, 2, 3]]
#restore
sub[0] = l1
print(sub)
# [[1, 2, 3], [1, 2, 3]]
switcher(sub[0])
print(sub)
#[[2, 1, 3], [2, 1, 3]]