2012-04-14 3 views
1

Я вижу статью о неизменяемом объекте.Постоянный объект в python

Он говорит, когда:
variable = immutable
Как присвоить неизменное переменной.

, например
a = b # b is a immutable
Это говорит в этом случае a относится к a copy of b, не reference to b. Если б это mutable, то a WIIL быть a reference to b

так:

a = 10 
b = a 
a =20 
print (b) #b still is 10 

, но в этом случае:

a = 10 
b = 10 
a is b # return True 
print id(10) 
print id(a) 
print id(b) # id(a) == id(b) == id(10) 

если a является копией 10 и b также является копией от 10, почему id(a) == id(b) == id(10)?

+0

Это не только переменчивость, но разница между указывая местоположение внутри объекта на новом объекте (при наличии 'некоторое_имя [some_item]' на левой стороне a '=') и указывая _name_ на новый объект (имея только 'some_name' в левой части' = '). Поэтому, если у вас есть 'inner = [0]' и 'внешний = [внутренний, внутренний]', если вы выполняете 'external [0] = 1', вы не меняете внутреннюю, а' outer' становится '[1, [ 0]] '. Поэтому, даже если 'inner' изменен, вы не изменяете его, если вы не получаете доступ к местоположению в нем, делая' external [0] [0] 'например, где вторая' [0] 'указывает внутри' inner'. – agf

ответ

5

Хотя эта статья может быть правильной для некоторых языков, это неправильно для Python.

Когда вы любого нормального назначения в Python:

some_name = some_name_or_object 

Вы не делаете копию чего-либо. Вы просто указываете имя на объекте с правой стороны задания.

Мутируемость не имеет значения.

Более конкретно, причина:

a = 10 
b = 10 
a is b 

является True, что 10 интернирован - это означает, Python хранит один 10 в памяти, и все, что устанавливается в 10 указывает на тот же 10.

Если вы

a = object() 
b = object() 
a is b 

Вы получите False, но

a = object() 
b = a 
a is b 

еще будет True.

+2

Python пытается ставить значения 'int', но не всегда получается. Попробуйте 'a = 1000' и' b = 999', а затем 'b + = 1'. Когда я попробовал это только сейчас, 'a' и' b' были привязаны к другому объекту 'int' со значением 1000. Я думаю, что интернирование всегда будет успешным для значений 0 и 1. – steveha

+0

этот случай: 'lst = [0, 1, 2] * 2', список [0, 1, 2] изменен, и я меняю' lst [0] [0] = 5', lst [1] [0] также изменится на 5, почему? –

+1

@steveha Это не удается или не удастся, это от 1 до 255, как сказал Игнасио в своем ответе. – agf

3

«Простые» неизменяемые литералы (и, в частности, целые числа от -1 до 255) являются интернированным, что означает, что даже при привязке к различным именам они все равно будут тем же объектом.

>>> a = 'foo' 
>>> b = 'foo' 
>>> a is b 
True 
+0

Это не объясняет всю первую две трети его поста, только последнюю треть. – agf

+0

@agf: Последняя треть - это та часть, которая имеет вопрос. –

+0

Все еще важно указать, что вывод, который он делает из прочитанной статьи, неверен. – agf

2

Поскольку интернирование уже пояснялось, я буду обращаться только изменяемые/неизменный материал:

Как присвоить неизменное переменной.

Говоря о том, что на самом деле происходит, я бы не выбрал эту формулировку.

У нас есть объекты (вещи, которые хранятся в памяти) и средства доступа к этим объектам: имена (или переменные), они привязаны к объекту в ссылке. (Вы могли бы указать точку на объекты)

Имена/переменные не зависят друг от друга, они могут быть связаны с одним и тем же объектом или с разными. Перемещение одной такой переменной не затрагивает других.

Нет такой вещи, как передача по значению или передача по ссылке. В 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] - это содержит тот же самый объект дважды.

Смежные вопросы