浅拷贝:为什么列表更改但不是字符串?

时间:2013-07-25 18:12:49

标签: python shallow-copy

据我所知,当您执行字典的浅表副本时,实际上会复制引用。所以,如果我这样做:

x={'key':['a','b','c']}
y=x.copy()

因此列表['a','b','c']的引用被复制到y中。每当我更改列表(例如x['key'].remove('a'))时,dict x和y都会改变。这一部分我明白了。但是当我考虑下面的情况时:

x={'user':'admin','key':['a','b','c']}
y=x.copy()

当我执行y['user']='guest'时,x ['user']不会更改,但列表仍然共享相同的引用。 所以我的问题是什么使字符串不同于列表?这背后的机制是什么?

2 个答案:

答案 0 :(得分:14)

你做了两件不同的事情。当你这样做

x['key'].remove('a')

你改变x['key']引用的对象。如果另一个变量引用同一个对象,您也会从该角度看到更改:

Pythontutor visualization Pythontutor visualization 2

然而,在第二种情况下,情况有所不同:

PT vis 3

如果你这样做

y['user']='guest'

重新绑定 y['user']到一个新对象。这当然不会影响x['user']或它引用的对象。

顺便说一句,这与可变对象和不可变对象无关。如果你做了

x['key'] = [1,2,3]

你也不会改变y['key']

PT vis 4

PythonTutor.com上以交互方式查看。

答案 1 :(得分:5)

不同之处在于,在一种情况下,您要为字典键分配新值,而在另一种情况下,您正在修改现有值。请注意两段代码的区别:

x['key'].remove('a')

此处没有=标志。你没有在字典中分配任何东西。事实上,这本词典甚至“不知道”发生了什么。你只是进入并操纵字典中的一个对象。

y['user'] = 'guest'

在这里,您实际上是为字典键分配了一个新值。

在第二种情况下,您无法执行等效的remove,因为字符串是不可变的。但是,差异不是“因为字符串是不可变的”。区别在于你正在改变列表而不是字符串。您可以通过执行

来获取第一个案例中第二个示例的行为
x['key'] = ['new', 'list']

这会为x中的密钥分配一个新值,使y不受影响。