присвоение значения в python dict (копия с ссылкой)

Я понимаю, что в python каждая вещь, будь то число, строка, dict или что-либо – объект. Имя переменной просто указывает на объект в памяти. Теперь, согласно этому вопросу ,

>> a_dict = b_dict = c_dict = {}

Это создает пустой словарь, и все переменные указывают на этот объект dict. Таким образом, изменение любого из них будет отражено в других переменных.

 >> a_dict["key"] = "value" #say >> print a_dict >> print b_dict >> print c_dict 

даст

 {'key': value} {'key': value} {'key': value} 

Я понял понятие переменных, указывающих на объекты, так что это кажется достаточно справедливым.

Теперь, хотя это может быть странно, поскольку это такое основное утверждение, почему это происходит?

 >> a = b = c = 1 >> a += 1 >> print a, b, c 2, 1, 1 # and not 2, 2, 2 

Первая часть вопроса: почему здесь не применяется такая же концепция?

На самом деле это сомнение возникло, когда я пытался найти решение для этого:

 >> a_dict = {} >> some_var = "old_value" >> a_dict['key'] = some_var >> some_var = "new_value" >> print a_dict {'key': 'old_value'} # and not {'key': 'new_value'} 

Это казалось противоречивым, поскольку я всегда считал, что я говорю, что словарь содержит переменную, и изменение объекта, на которое указывает указатель, очевидно отразится в словаре. Но мне кажется, что значение копируется, а не указано. Это было второе, что я не понял.

Двигаясь дальше, я попробовал что-то еще

 >> class some_class(object): .. def __init__(self): .. self.var = "old_value" >> some_object = some_class() >> a_dict = {} >> a_dict['key'] = some_object >> some_object.var = "new_value" >> print a_dict['key'].var "new_value" # even though this was what i wanted and expected, it conflicts with the output in the previous code 

Теперь, здесь, очевидно, на это ссылались. Эти противоречия оставили меня в замешательстве в непредсказуемой природе питона, хотя я все еще люблю его, потому что я не знаю какого-либо другого языка достаточно хорошо: p. Хотя я всегда думал, что задания приводят к ссылке на объект, однако эти два случая противоречат друг другу. Так что это мое последнее сомнение . Я понимаю, что это может быть один из них. Пожалуйста, просветите меня.

Вы боретесь с двумя разными вещами. Первая – это идея изменчивости и неизменности . В python, str , int , tuple являются некоторыми встроенными неизменяемыми типами по сравнению с list , dict (и другими), которые являются изменяемыми типами. неизменяемые объекты – это те, которые не могут быть изменены после их создания. Итак, в вашем примере:

 a = b = c = 1 

После этой строки все a , b и c относятся к одному и тому же целому числу в памяти (вы можете проверить, распечатав их id respecitve и отметив, что они одинаковы). Однако, когда вы это делаете:

 a += 1 

a теперь ссылается на новое (другое) целое число в другой ячейке памяти. Обратите внимание, что в качестве соглашения += должен возвращать новый экземпляр чего-либо, если этот тип является неизменным. Если тип изменен , он должен изменить объект на место и вернуть его. В этом ответе я объясню некоторые более подробные детали.


Во второй части вы пытаетесь выяснить, как работают идентификаторы python. То, как я думаю об этом, это … когда вы пишете заявление:

 name = something 

Правая часть оценивается на некоторый объект (целое число, строка, …). Затем этому объекту присваивается имя в левой части 1 . Когда имя находится справа, соответствующий объект автоматически «просматривается» и заменяется именем в расчете. Обратите внимание, что в этой структуре назначение не имеет значения, если что-либо имеет это имя раньше – оно просто перезаписывает старое значение новым. Объекты, которые ранее были построены с использованием этого имени, также не видят никаких изменений. Они уже созданы, сохраняя ссылки на сами объекты, а не на имена. Так:

 a = "foo" # `a` is the name of the string "foo" b = {"bar": a} # evaluate the new dictionary and name it `b`. `a` is looked up and returns "foo" in this calculation a = "bar" # give the object "bar" the name `a` irrespecitve of what previously had that name 

1 Я просто замалчиваю несколько деталей для простоты – например, что происходит, когда вы назначаете элемент списка: lst[idx] = some_value * some_other_value .

Это связано с тем, что += можно интерпретировать как a = a + 1 , который перепровергает переменную a на значение a + 1 , то есть 2 .

Аналогично, some_var = "new_value" new_value some_var = "new_value" перепроверяет переменную, и объект не изменяется, поэтому пара ключей, значений в словаре все еще указывает на этот объект.

В последнем примере вы не перепроверяете, а мутируете объект, поэтому значение изменяется в словаре.