Переменные в Python - это имена объектов , а не места памяти , как в C ++. Переназначение имени просто меняет то, к чему относится имя; он не меняет референт или другие псевдонимы.
Ближайшим эквивалентом является указатель: в CPython присвоение имени, как в o2 = o1
, фактически означает PyObject *o2 = *o1
. Адрес скопирован с одного имени на другое. Не существует прямой связи между именами после присваивания - они просто все еще ссылаются на один и тот же объект.
>>> o1 = {1, 2, 3}
>>> o2 = o1
>>> print(id(o1), id(o2)) # the *referents* of o1 and o2 are at the same memory location
4444160520 4444160520
Когда два имени относятся к одному и тому же объекту, они показывают одно и то же состояние объекта - в конце концов, существует только одно состояние. Вот почему изменение o1.data
было видно также и через o2
- объект , на который ссылаются как o2
, так и o1
, был изменен.
>>> o1.add(16)
>>> print(o1, o2) # still the same referent, should have the same state
{16, 1, 2, 3} {16, 1, 2, 3}
>>> print(id(o1), id(o2)) # both still have the same referent
4444160520 4444160520
Хитрость в том, что хотя o1
и o2
являются отдельными, такие члены, как o1.data
и o2.data
не являются! Каждое имя верхнего уровня является отдельной сущностью. Однако атрибуты и тому подобное относятся к их объекту!
При переназначении изменяется только имя, назначенное для. Помните, что o2
скопировал ссылку из o1
- нет никакого отношения, на которое может повлиять изменение имени o1
.
>>> o1 = None
>>> print(o1, o2) # not the same referent anymore
None {16, 1, 2, 3}
>>> print(id(o1), id(o2)) # only o2 still refers to the same referent
4436169032 4444160520