字典中的可变性

时间:2017-12-03 09:06:37

标签: python mutability

>>> mydict = {1: {45: 'ades', 54:'adee'}, 2: {68: 'gdes'}}
>>> curr_value = mydict[1][45]
>>> mydict[1][45] = 'zzzz'
>>> print (curr_value)
ades  # Expected value: zzzz

我的curr_value怎么没有从mydict变异?我没有克隆curr_value或任何东西。

3 个答案:

答案 0 :(得分:0)

mydict = {1: {45: 'ades', 54:'adee'}, 2: {68: 'gdes'}}
curr_value = mydict[1][45]
mydict[1][45] = 'zzzz'
print (curr_value)
print(mydict)

输出:

ades
{1: {45: 'zzzz', 54: 'adee'}, 2: {68: 'gdes'}

你的字典是可变的 - 它被改变了。 curr_value是一个字符串,不可变。

中间的想法:

def boll(tpl):
    return mydict[tpl[0]][tpl[1]]

mydict = {1: {45: 'ades', 54:'adee'}, 2: {68: 'gdes'}}
curr_value = (1,45)
print (boll(curr_value))
mydict[1][45] = 'zzzz'
print (boll(curr_value)) 

这只是一个记忆你想要引用的dict中的点的封装,并且函数可以在你调用它时获得dict的值。

答案 1 :(得分:0)

当更新某些其他数据结构时,无法创建一个“更新”自身的普通变量。这种行为只能通过表达式来实现,比如属性或项目查找。换句话说,您可以创建一个对象curr_value,以便评估curr_value[0]在此时为您提供mydict[1][45]的值,或者评估curr_value.value会为您提供mydict[1][45]的值1}}在那一刻,但是你无法做到这一点,因此仅仅评估普通curr_value会给你mydict[1][45]的价值。执行curr_value = mydict[1][45] 始终会将curr_value设置为您分配时的内容,如果mydict[1][45]发生更改,则不会在以后更新。

答案 2 :(得分:0)

您想要的是不可能的,因为简单的赋值总是创建一个新的绑定(即,将新对象绑定到=符号的LHS上的名称)。 OTOH,执行突变不会创建新的绑定,所以你可以这样做,例如

ref = mydict[1]
mydict[1][45] = 'zzzz'
print(ref[45]) 

根据需要打印zzzz

Stack Overflow资深人士Ned Batchelder在Facts and myths about Python names and values中很好地介绍了这个主题,并在Other languages have "variables", Python has "names"中进行了总结。

另一个选择是

mydict = {1: {45: ['ades'], 54:['adee']}, 2: {68: ['gdes']}}
ref = mydict[1][45]
mydict[1][45][0]='zzzz'
print(ref[0]) 

一般来说,最好避免像这样造成混乱,但有时候这种事情很有用。例如,通过向2D列表添加额外的间接层,我们可以通过列和行来访问它。

# Create the grid
rows = [[[u+v] for u in 'abcd'] for v in 'wxyz']
cols = [list(u) for u in zip(*rows)]
print(rows)
print(cols)
print()

# Mutate some grid cells
cell = rows[1][2]
cell[0] = cell[0].upper()
cell = cols[0][3]
cell[0] = cell[0].upper()

print(rows)
print(cols)

<强>输出

[[['aw'], ['bw'], ['cw'], ['dw']], [['ax'], ['bx'], ['cx'], ['dx']], [['ay'], ['by'], ['cy'], ['dy']], [['az'], ['bz'], ['cz'], ['dz']]]
[[['aw'], ['ax'], ['ay'], ['az']], [['bw'], ['bx'], ['by'], ['bz']], [['cw'], ['cx'], ['cy'], ['cz']], [['dw'], ['dx'], ['dy'], ['dz']]]

[[['aw'], ['bw'], ['cw'], ['dw']], [['ax'], ['bx'], ['CX'], ['dx']], [['ay'], ['by'], ['cy'], ['dy']], [['AZ'], ['bz'], ['cz'], ['dz']]]
[[['aw'], ['ax'], ['ay'], ['AZ']], [['bw'], ['bx'], ['by'], ['bz']], [['cw'], ['CX'], ['cy'], ['cz']], [['dw'], ['dx'], ['dy'], ['dz']]]

在这个答案开始时,我说“简单分配总是创建一个新的绑定”。但是,augmented assignment将在可能的情况下执行就地操作,即目标是可变对象。来自文档:

  

可以将像x += 1这样的扩充分配表达式重写为   x = x + 1实现类似但不完全相同的效果。在里面   增强版本,x仅评估一次。另外,如果可能的话   实际操作是就地执行的,而不是   创建一个新对象并将其分配给目标,即旧对象   而是被修改了。