Изменчивость в словаре

>>> 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 ответа

Нет способа создать простую переменную, которая "обновляет" себя, когда обновляется какая-то другая структура данных. Такое поведение может быть достигнуто только с помощью таких выражений, как поиск атрибутов или элементов. Другими словами, вы можете сделать объект curr_value так что оценивая curr_value[0] дает вам значение mydict[1][45] в тот момент, или оценивая curr_value.value дает вам значение mydict[1][45] в этот момент, но вы не можете сделать так, чтобы оценка просто curr_value дает вам значение mydict[1][45] в тот момент. дела curr_value = mydict[1][45] всегда устанавливает curr_value к тому, что это в данный момент, вы назначаете его, и он не будет обновляться позже, если mydict[1][45] изменения.

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 в тот момент, когда вы его называете.

То, что вы хотите, не возможно, потому что простое назначение всегда создает новую привязку (т. Е. Привязывает новый объект к имени на LHS = знак). OTOH, выполнение мутации не создает новую привязку, так что вы можете сделать, например,

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

который печатает zzzz по желанию.

Эта тема хорошо освещена ветераном Stack Overflow Недом Батчелдером в " Фактах и ​​мифах об именах и значениях Python", а в " Других языках" есть "переменные", в Python "имена".

Другой вариант сделать

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']]]

В начале этого ответа я заявил, что "простое назначение всегда создает новую привязку". Однако расширенное присваивание будет выполнять операцию на месте, когда это возможно, то есть цель является изменяемым объектом. Из документов:

Расширенное выражение присваивания, как x += 1 может быть переписан как x = x + 1 добиться аналогичного, но не совсем равного эффекта. В расширенной версии x оценивается только один раз. Кроме того, когда это возможно, фактическая операция выполняется на месте, что означает, что вместо создания нового объекта и назначения его цели, старый объект вместо этого изменяется.

Другие вопросы по тегам