Что происходит, когда вы присвоить значение одной переменной другой переменной в Python?


это мой второй день обучения python (я знаю основы C++ и некоторые ООП.), и у меня есть небольшая путаница относительно переменных в python.

вот как я понимаю их в настоящее время:

переменные Python являются ссылками (или указателями?) к объектам (которые являются либо изменяемыми, либо неизменяемыми). Когда у нас есть что-то вроде num = 5, неизменяемого объекта 5 создается где-то в памяти, а имя-объект ссылочной пары num создается в определенное пространство имен. Когда у нас есть a = num ничего не копируется, но теперь обе переменные ссылаются на тот же объект и a добавляется в то же пространство имен.

вот где моя книга,автоматизировать скучные вещи с Python, смущает меня. Поскольку это книга для новичков, в ней не упоминаются объекты, пространства имен и т. д. и он пытается объяснить следующий код:

>>> spam = 42
>>> cheese = spam
>>> spam = 100
>>> spam
100
>>> cheese
42

объяснение, которое он предлагает, точно такое же, как у книги на C++, которой я не являюсь рад, что мы имеем дело со ссылками/указателями на объекты. Поэтому в этом случае я предполагаю, что в 3-й строке, поскольку целые числа неизменяемы,spam присваивается совершенно новый указатель / ссылка на другое место в памяти, т. е. память, на которую он первоначально указывал, не была изменена. Следовательно, мы имеем cheese ссылка на исходный объект, на который ссылается spam. Это правильное объяснение?

8 71

8 ответов:

как разработчик C++ вы можете думать о переменных Python как указатели.

таким образом, когда вы пишите spam = 100, Это означает, что вы" назначаете указатель", который ранее указывал на объект 42, чтобы указать на объект 100.

ранее, cheese было назначено указать на тот же объект, что и spam указал на то, что случилось 42 в то время. Так как вы не изменили cheese, он по-прежнему указывает на 42.

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

Как я вижу, есть разные взгляды на язык.

  • перспектива "языкового адвоката".
  • перспектива "практического программиста".
  • перспектива "исполнитель".

с точки зрения юриста языка переменные python всегда "указывают" на объект. Однако в отличие от Java и C++ поведение == = etc зависит от типа времени выполнения объектов, на которые указывают переменные. Кроме того, в python управление памятью осуществляется языком.

с практической точки зрения программиста мы можем рассматривать тот факт, что целые числа, строки, кортежи и т. д. являются неизменяемыми* объектами, а не прямыми значениями как неуместную деталь. Исключение-при хранении больших количеств числовых данных мы можем использовать типы, которые могут хранить значения напрямую (например, массивы numpy), а не типы, которые в конечном итоге будут содержать массив, полный ссылок на крошечные объекты.

от у большинства языков есть какое-то правило as-if, так что если заданное поведение правильно, реализация правильна независимо от того, как на самом деле все делается под капотом.

Так что да ваше объяснение правильно с точки зрения юриста языка. Ваша книга верна с практической точки зрения программиста. Что реализация действительно зависит от реализации. В с CPython чисел представляют собой реальные объекты, хоть и малое значение числа берется из пула кэша, а не создается заново. Я не уверен, что делают другие реализации (например, pypy и jython).

* обратите внимание на различие между изменяемыми и неизменяемыми объектами. С изменяемым объектом мы должны быть осторожны, рассматривая его "как значение", потому что какой-то другой код может его мутировать. С неизменным объектом у нас таких забот нет.

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

во-первых, мы будем активно использовать id функция:

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

вероятно, это вернет различные абсолютные значения на вашем компьютере.

Рассмотрим пример:

>>> foo = 'a string'
>>> id(foo) 
4565302640
>>> bar = 'a different string'
>>> id(bar)
4565321816
>>> bar = foo
>>> id(bar) == id(foo)
True
>>> id(bar)
4565302640

вы можете увидеть, что:

  • исходные foo / bar имеют разные идентификаторы, потому что они указывают на разные объекты
  • когда бар назначается foo, их идентификаторы теперь одинаковы. Это похоже на то, что они оба указывают на одно и то же место в памяти, которое вы видите при создании C++ указатель

когда мы меняем значение foo, ему присваивается другой идентификатор:

>>> foo = 42
>>> id(foo)
4561661488
>>> foo = 'oh no'
>>> id(foo)
4565257832

интересным наблюдением также является то, что целые числа неявно имеют эту функциональность до 256:

>>> a = 100
>>> b = 100
>>> c = 100
>>> id(a) == id(b) == id(c)
True

однако за 256 это уже не так:

>>> a = 256
>>> b = 256
>>> id(a) == id(b)
True
>>> a = 257
>>> b = 257
>>> id(a) == id(b)
False
назначение a до b действительно сохранит идентификатор таким же, как показано ранее:
>>> a = b
>>> id(a) == id(b)
True

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

подумайте об этом как "pass-by-alias", если вам нужен тот же тип фразы или, возможно, "pass-by-object", потому что вы можете мутировать один и тот же объект из любой переменной, которая указывает на него, если он изменчив, но переназначение переменной (псевдоним) изменяет только эту переменную.

Если помощь: переменные C-это поля, в которые вы записываете значения. Имена Python-это теги, которые вы ставите на значения.

имя переменной Python является ключом в глобальном (или локальном) пространстве имен, которое фактически является словарем. Базовое значение-это некоторый объект в памяти. Присваивание дает имя этому объекту. Присвоение одной переменной другой переменной означает, что обе переменные являются названиями одного и того же объекта. Повторное присвоение одной переменной изменяет то, какой объект назван этой переменной без изменения другой переменной. Вы переместили тег, но не изменили предыдущий объект или любые другие теги на нем.

в базовом коде C реализации CPython каждый объект Python является PyObject*, поэтому вы можете думать об этом как о работе, как C, если у вас когда-либо были указатели на данные (нет указателей на указатели, нет непосредственно переданных значений).

можно сказать, что Python-это pass-by-value, где значения являются указателями... или вы можете сказать, что Python pass-by-reference, где ссылки являются копиями.

при выполнении spam = 100 python создает еще один объект в памяти, но не изменяет существующий. так что у вас все еще есть указатель cheese на 42 и spam до 100

что происходит в spam = 100 строка-это замена предыдущего значения (указатель на объект типа int со значением 42) с другим указателем на другой объект (тип int, value 100)

Как упоминалось в комментариях @DeepSpace, Ned Batchelder отлично справляется с демистификацией переменных (имен) и назначений значений в блоге, из которого он выступил с докладом на PyCon 2015,факты и мифы об именах Python и ценностей. Это может быть проницательным для питонистов на любом уровне мастерства.

когда вы в магазине spam = 42 , Он создает объект в памяти. Тогда вы назначаете cheese = spam, он назначает объект, на который ссылается spam до cheese. И, наконец, когда вы меняете spam = 100, Он изменяет только