Переменные в python являются просто именами для объекта, и присвоение им просто меняет объект, обозначенный этим именем.
Однако при назначении элементам списка вы меняете объект, на который ссылается эта позиция в списке.
Таким образом:
pointer = self.storage[index] # 1
pointer = pointer.next # 2
self.storage[index] = self.storage[index].next # 3
(1) Делает pointer
имя для объекта, на который ссылается storage[index]
(2) Вкл. В правой части присваивания =
вы ищете атрибут name
объекта, на который ссылается pointer
. Это self.storage[index].name
. При присвоении переменная pointer
будет ссылаться на self.storage[index].name
. Чтобы обновить список self.storage
, вам нужно работать с самим объектом списка. В отличие от self.storage[index]
, на который ссылается pointer
, это просто «некоторый объект». У вас даже нет способа вернуться к списку оттуда, поэтому здесь невозможно изменить список.
(3) Здесь, однако, вы меняете список self.storage
, заменяя элемент в index. You could have done
self.storage [index] = pointer` в этот момент, с тем же эффектом.
Конечно python работает со ссылками (или указателями) под капотом. my_list[1] = obj
не выделяет место для obj
, он будет хранить ссылку на него. Но локальные и глобальные переменные не являются ссылками, это имена.
В конце концов, глобальные и локальные пространства имен просто отображают имена переменных в объектах. Обычно это обычные словари. Вы можете увидеть их, позвонив globals()
и locals()
. Или вы можете «реализовать» назначение переменных, просто изменив этот словарь:
foo = 1
globals()["foo"] = 2
print(foo) # --> 2
Python назначение переменных отличается от назначения изменяемым объектам, таким как списки или словари. Давайте рассмотрим следующие утверждения:
a = 1 # 1
b = [1] # 2
b[0] = 2 # 3
Первые два назначения делают то же самое. Они создают (или обновляют) глобальные переменные a
и b
и сопоставляют их с int
объектом 1
и list
объектом [1]
соответственно. У вас будет:
globals()
{
...
"a": 1,
"b": [1]
...
}
Третье назначение совершенно другое. Присвоение этого типа фактически осуществляется объектом слева. Из документов:
Когда цель является частью изменяемого объекта (ссылка на атрибут, подписка или вырезка), изменяемый объект должен в конечном итоге выполнить назначение и принять решение о его допустимости и может вызвать исключение, если присвоение недопустимо.
Это означает, что третье утверждение реализуется самим объектом списка. Теперь список в python содержит ссылки на объекты (он не копирует объекты). b[0]
, когда используется в выражении, реализуется специальным методом объекта списка и возвращает объект, на который ссылается список в позиции 0. b[0] = 2
фактически вызывает специальный метод объекта списка с индексом (0) и целевой объект (2) в качестве аргументов, и реализация списка решает, как она обновляет себя: она изменит ссылку на индекс 0 на новый объект.
Эта разница встроена в python оператор присваивания. Мне тоже понравилась полная ссылка.
Подробнее: