Поскольку интернирование уже пояснялось, я буду обращаться только изменяемые/неизменный материал:
Как присвоить неизменное переменной.
Говоря о том, что на самом деле происходит, я бы не выбрал эту формулировку.
У нас есть объекты (вещи, которые хранятся в памяти) и средства доступа к этим объектам: имена (или переменные), они привязаны к объекту в ссылке. (Вы могли бы указать точку на объекты)
Имена/переменные не зависят друг от друга, они могут быть связаны с одним и тем же объектом или с разными. Перемещение одной такой переменной не затрагивает других.
Нет такой вещи, как передача по значению или передача по ссылке. В Python вы всегда передать/присвоить «по объекту». При назначении или передаче переменной функции Python никогда не создает копию, она всегда передает/присваивает тот же самый объект, который у вас уже есть.
Теперь, когда вы пытаетесь изменить неизменяемый объект, что происходит? Как уже было сказано, объект неизменен, поэтому вместо этого происходит следующее: Python создает измененную копию .
Что касается вашего примера:
a = 10
b = a
a =20
print (b) #b still is 10
Это не связано с изменчивостью. В первой строке вы связываете объект int со значением 10
с именем a
. Во второй строке вы связываете объект, на который ссылается a
, с именем b
.
На третьей строке вы связываете объект int со значением 20
с именем a
, который не меняет то, на что связано имя b
!
В нем говорится, что в этом случае ссылка ссылается на копию b, а не ссылку на b. Если б изменчиво, а-WIIL быть ссылкой б
Как уже упоминалось ранее, не существует такого понятия, как ссылки в Python. Имена в Python привязаны к объектам. Различные имена (или переменные) могут быть привязаны к одному и тому же объекту, но нет никакой связи между разными именами. Когда вы меняете вещи, вы изменяете объекты , поэтому все другие имена, привязанные к этому объекту, «видят изменения», ну, они связаны с тем же измененным объектом, верно?
Если вы связываете имя с другим объектом, это именно то, что происходит. Для других имен нет волшебства, они остаются такими, какие они есть.
Что касается примера со списками:
In [1]: smalllist = [0, 1, 2]
In [2]: biglist = [smalllist]
In [3]: biglist
Out[3]: [[0, 1, 2]]
Вместо того, в [1] и в [2], я мог бы написать:
In [1]: biglist = [[0, 1, 2]]
In [2]: smalllist = biglist[0]
Это эквивалентно.
Важная вещь, чтобы увидеть здесь, заключается в том, что biglist - это список с одним элементом. Этот предмет, конечно, является объектом.Тот факт, что это список, не вызывает никакой магии, это просто простой объект, который является списком, который мы привязали к имени smalllist
.
Таким образом, доступ к biglist [i] в точности совпадает с доступом к мелкому списку, поскольку они являются одним и тем же объектом. Мы никогда не делали копию, мы передавали объект.
In [14]: smalllist is biglist[0]
Out[14]: True
Поскольку списки являются изменяемыми, мы можем изменить малый размер и увидеть изменение, отраженное в списке. Зачем? Потому что мы фактически модифицировали объект, на который ссылается малый. У нас все еще есть один и тот же объект (кроме того, что он изменился). Но biglist «увидит» это изменение, потому что в качестве первого элемента он ссылается на тот же самый объект.
In [4]: smalllist[0] = 3
In [5]: biglist
Out[5]: [[3, 1, 2]]
То же самое верно, когда мы "двойной" список:
In [11]: biglist *= 2
In [12]: biglist
Out[12]: [[0, 1, 2], [0, 1, 2]]
Что происходит: У нас есть список: [object1, object2, object3] (это общий пример) Что мы получаем: [object1, object2, object3, object1, object2, object3]: будет только вставить (т. Е. Изменить «большой список») всех элементов в конце списка. Опять же, мы вставляем объекты, мы не волшебным образом создаем копии.
Так что, когда мы теперь изменить элемент внутри первого элемента biglist:
In [20]: biglist[0][0]=3
In [21]: biglist
Out[21]: [[3, 1, 2], [3, 1, 2]]
Мы также могли бы просто изменили smalllist
, потому что для всех намерений и целей, biglist
может быть представлена как: [smalllist, smalllist]
- это содержит тот же самый объект дважды.
Это не только переменчивость, но разница между указывая местоположение внутри объекта на новом объекте (при наличии 'некоторое_имя [some_item]' на левой стороне a '=') и указывая _name_ на новый объект (имея только 'some_name' в левой части' = '). Поэтому, если у вас есть 'inner = [0]' и 'внешний = [внутренний, внутренний]', если вы выполняете 'external [0] = 1', вы не меняете внутреннюю, а' outer' становится '[1, [ 0]] '. Поэтому, даже если 'inner' изменен, вы не изменяете его, если вы не получаете доступ к местоположению в нем, делая' external [0] [0] 'например, где вторая' [0] 'указывает внутри' inner'. – agf