2015-11-05 93 views
5

最近我已经做了2个实验:为什么在dict中的值总是在Python中改变了?

(1):

>>> a = dict(zip([1,2,3],[4]*3)) 
>>> a 
{1: 4, 2: 4, 3: 4} 

>>> a[1] = 111  
>>> a 
{1: 111, 2: 4, 3: 4} 

(2):

>>> a = dict(zip([1,2,3],[{'a':True,'b':True}]*3)) 
>>> a 
{1: {'a': True, 'b': True}, 
2: {'a': True, 'b': True}, 
3: {'a': True, 'b': True}} 

>>> a[1]['a']=False # Here I changed the value of a[1]['a'] from True to False  
>>> a 
{1: {'a': False, 'b': True}, 
2: {'a': False, 'b': True}, 
3: {'a': False, 'b': True}}  #all 'a' value changed to False. 

为什么(2)发生在这个问题呢?为什么(1)没有这个问题?

回答

7

简短回答:因为dict对象是可变的,并且int对象是不可变的。

详情:

[{'a': True, 'b': True}] * 3

随着

>>> l = [{}] * 3 

您创建一个包含引用同一个对象3次名单。

>>> id(l[0]) 
139685186829320 
>>> id(l[1]) 
139685186829320 
>>> id(l[2]) 
139685186829320 

所以,当你改变其中之一,你改变他们全部(在可变对象的情况下)。

如果你想不同的字典列表,你可以做到这一点:

>>> l = [{} for x in range(3)] 
>>> id(l[0]) 
139685161766216 
>>> id(l[1]) 
139685161766536 
>>> id(l[2]) 
139685161766600 

在你的情况应该是这样的:

a = dict(zip([1, 2, 3], [{'a': True, 'b': True} for i in range(3)])) 

有了不可改变的对象是不同的

您无法更改不可变对象。任何看起来像你改变不可变对象的地方,都会创建一个新的对象。

所以,当你尝试改变内部列表不可变对象,将创建一个新的对象:

>>> l = [1] * 3 

>>> id(l[0]) 
139685185487008 
>>> id(l[1]) 
139685185487008 
>>> id(l[2]) 
139685185487008 

>>> l[0] = 2 

>>> id(l[0]) 
139685185487040 # new object created instead of old object being modified 
>>> id(l[1]) 
139685185487008 
>>> id(l[2]) 
139685185487008 
0

如果使用列表理解(更换ZIP)或为()循环,你不会使用相同的对象3次

a = {ctr:{'a':True,'b':True} for ctr in range(1, 4)} 
print a 
a[1]['a']=False 
print a 
相关问题