Как происходит процесс присваивания в python данные связываются ссылками на объекты
Перейти к содержимому

Как происходит процесс присваивания в python данные связываются ссылками на объекты

  • автор:

Инструкции присваивания в Python

В Python , как и во многих других языках программирования, каноническая форма операции присваивания имеет вид a = b , где слева от оператора присваивания записывается целевое имя переменной или компонент объекта, а в качестве правого операнда выступает произвольное выражение, которое в результате вычислений дает объект (см. пример №1 ).

Пример №1. Каноническая форма присваивания.

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

  • Инструкции присваивания всегда сохраняют ссылки на объекты, например, в переменных или в элементах структур данных, и никогда не создают копии присваиваемых объектов. Как следствие, переменные в Python больше напоминают указатели, чем области хранения данных.
  • Объявлять переменные заранее нельзя, т.к. интерпретатор создает переменные в момент присваивания им значений (то есть ссылок на объекты). После инициализации, когда имя переменной будет встречаться в выражениях, оно будет автоматически замещаться объектом, на который ссылается данная переменная. Если же интерпретатор встретит в программе неинициализированную переменную, он возбудит исключение вместо того, чтобы вернуть какое-либо значение по умолчанию (такое поведение призвано облегчить поиск ошибок и опечаток в коде).
  • Некоторые инструкции пусть и неявно, но тоже выполняют операцию присваивания. Примерами могут служить импорт модуля, определение функции или класса, указание переменной в цикле for или же передача аргументов функции. В любом случае результатом явных или неявных инструкций присваивания будет связывание имен с ссылками на объекты.

Ну, и в конце пункта еще раз напомним, что в программировании знак равно ( = ) обычно означает не равенство двух величин, а присваивание значения переменной. Если же нужно указать на равенство двух значений, то используется комбинация символов из двух знаков равно ( == ).

Комбинированные инструкции присваивания

В дополнение к базовой инструкции присваивания в Python имеется и целый ряд комбинированных инструкций присваивания, которые объединяют операцию присваивания с другой операцией. В общем виде инструкцию присваивания с комбинированным оператором x operator= y можно считать сокращенной записью инструкции x = x operator y . Например, x += y является сокращенной записью инструкции присваивания x = x + y , в которой к значению переменной x прибавляется значение переменной y , а результат присваивается переменной x (см. пример №2 ).

Пример №2. Комбинированная форма присваивания.

Таким образом, комбинированная инструкция присваивания объединяет в себе выражение и присваивание, являясь по сути краткой формой записи кода. И хотя, например, инструкции num += 25 и num = num + 25 дадут один и тот же результат, первая из них выглядит явно компактнее. Кроме того, если объект справа относится к категории изменяемых объектов и поддерживает указанную операцию, комбинированная инструкция присваивания может выполняться даже быстрее за счет непосредственного изменения объекта вместо создания и изменения его копии (см. пример №3 ).

Пример №3. Преимущества комбинированной формы присваивания.

Метод time() одноименного модуля time стандартной библиотеки Python возвращает время, выраженное в секундах с начала эпохи. В операционных системах Unix , например, за начало эпохи принимается 1 января 1970 , 00 : 00 : 00 ( UTC ). Но поскольку в программах в основном используются интервалы времени между двумя событиями, а не время, прошедшее с начала эпохи, знать дату начала эпохи какой-либо конкретной операционной системы вовсе необязательно, т.к. разница между двумя временными точками для всех платформ получается совершенно одинаковой.

Давайте еще раз и в одном месте перечислим основные инструкции присваивания, комбинированные с арифметическими операторами:

  • a += b – тоже самое, что и a = a + b ;
  • a -= b – тоже самое, что и a = a — b ;
  • a *= b – тоже самое, что и a = a * b ;
  • a **= b – тоже самое, что и a = a**b ;
  • a /= b – тоже самое, что и a = a / b ;
  • a //= b – тоже самое, что и a = a // b ;
  • a %= b – тоже самое, что и a = a % b .

Позиционное присваивание

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

Пример №4. Позиционное присваивание (часть 1).

Как видим, данная форма присваивания позволяет смешивать последовательности разных типов. Здесь главное, чтобы количество присваиваемых значений совпадало с количеством переменных, которым эти значения будут присваиваться. Но и эта проблема может быть решена за счет имеющейся возможности использования в присваивании расширенного синтакиса распаковывания последовательностей (см. пример №5 ).

Пример №5. Позиционное присваивание (часть 2).

Благодаря наличию имени со звездочкой все лишние значения автоматически помещаются в соответсвующий список именно так, как и ожидается. Однако нужно не забывать, что можно использовать только одну переменную со звездочкой, а сама переменная должна принадлежать последовательности даже в том случае, если она будет одна (поставив запятую в инструкции *c, = [1, 2] мы автоматически получили кортеж и смогли избежать ошибки).

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

Групповое присваивание одного значения

В случае группового присваивания объект, расположенный справа, присваивается всем переменным группы (см. пример №6 ). В результате несколько отдельных инструкций присваивания могут быть заменены одной эквивалентной и более компактной инструкцией.

Пример №6. Присваивание одного значения группе переменных (часть 1).

Следует иметь в виду, что при групповом присваивании в памяти создается всего лишь один объект, разделяемый всеми переменными группы. Поэтому такая форма присваивания будет полезна для неизменяемых объектов, например, чисел или строк. А вот при использовании изменяемых объектов типа списков или словарей нужно быть осторожными, т.к. изменение объекта через одну из переменных группы будет оказывать влияние и на другие переменные (см. пример №7 ). Это связано с тем, что переменные в Python хранят не сами объекты, а ссылки на них. А раз так, то даже после изменения объекта через одну из ссылок все остальные по-прежнему будут указывать на тот же, пусть и модифицированный, объект.

Пример №7. Присваивание одного значения группе переменных (часть 2).

Таким образом, во избежание проблем с изменяемыми объектами, их инициализацию лучше производить в отдельных инструкциях, как было показано в первой части примера №6 .

Выражения присваивания в Python

Все рассмотренные нами формы присваивания относятся к инструкциям. Но их запрещено использовать в выражениях, что иногда может быть весьма полезным. Поэтому начиная с версии Python 3.8 было решено ввести новую конструкцию NAME := expr с возможностью использования в выражениях (см. пример №8 ). Конструкция получила название или же , а оператор := стал неофициально называться .

Пример №8. Использование выражений присваивания (часть 1).

Использовать выражение присваивания в коде верхнего уровня без скобок запрещается. Например, инструкция x = y := 5 не пройдет, нужно использовать скобки: x = (y := 5) . И вообще, использование скобок с моржовым оператором следует сразу же взять на вооружение, т.к. это поможет избежать многих досадных ошибок.

Возможно, кто-то сочтет такое нововведение нецелесообразным, ведь выражения порой и так бывают довольно громоздкими, чтобы вводить туда еще и дополнительные конструкции с набором ограничений. Но ситуации бывают разные как, например, в примере №9 .

Пример №9. Использование выражений присваивания (часть 2).

Подробнее о выражениях присваивания можете почитать на официальном сайте в документации к PEP 572 – Assignment Expressions.

Краткие итоги параграфа

  • В Python инструкции присваивания всегда сохраняют ссылки на объекты, например, в переменных или в элементах структур данных, и никогда не создают копии присваиваемых объектов.
  • Классическая форма присваивания имеет вид NAME = expr , что соответствует синтаксису многих других языков программирования. Однако в Python доступны и другие формы инструкций присваивания: комбинированные инструкции присваивания (например, y **= 3 ), позиционное присваивание (например, x, y = [3, 5] или x, *y = ‘abcdef’ ), а также групповое присваивание одного значения (например, a = b = c = 33 ).
  • При групповом присваивании одного значения в памяти создается всего лишь один объект, разделяемый всеми переменными группы. Поэтому такая форма присваивания будет полезна для неизменяемых объектов, например, чисел или строк. А вот при использовании изменяемых объектов типа списков или словарей нужно быть осторожными, т.к. изменение объекта через одну из переменных группы будет оказывать влияние и на другие переменные.
  • Поскольку в Python запрещается использовать инструкции в выражениях, начиная с версии 3.8 была введена специальная конструкция NAME := expr , получившая название выражения присваивания и предназначенная для присваивания значений внутри выражений, например, a = (b := 3) + (c := 5) .

Вопросы и задания для самоконтроля

1. Перечислите основные формы инструкций присваивания в Python . Показать решение.

Ответ. Классическая форма NAME = expr , комбинированные инструкции присваивания NAME operator= expr , позиционное присваивание NAME_1, . NAME_n = expr_1, . expr_n , а также групповое присваивание одного значения NAME_1 = . = NAME_n = expr .

2. Имеются две инициализированные переменные a = ‘one’ и b = ‘two’ . Поменяйте значения переменных местами, использовав позиционную форму инструкции присваивания. Показать решение.

Ответ. Так как в процессе позиционного присваивания интерпретатор создает временный кортеж, где сохраняются оригинальные значения переменных справа, данная форма присваивания может использоваться для реализации обмена значений переменных без создания временной переменной. Таким образом, кортеж справа автоматически запоминает предыдущие значения переменных.

3. О чем следует помнить, когда трем переменным присваивается один и тот же изменяемый объект? Показать решение.

Ответ. Если, например, выполнить присваивание следующим образом: a = b = c = [] , то все три переменные будут ссылаться на один и тот же объект. Поэтому непосредственное изменение объекта с помощью одной переменной (например, A.append(5) ) отразится и на других. Однако это справедливо только для изменений, производимых непосредственно в изменяемых объектах, таких как списки или словари. Для неизменяемых объектов, вроде чисел и строк, такой проблемы не возникает.

4. Какие из представленных фрагментов кода содержат ошибки: a, b = [3, ‘3’] ; x, *y = 1, 2, 3 ; *x, = 1, 2, 3 ; *x, y, *z = 1, 2, 3, 4 ? Объясните ответ. Показать решение.

Ответ. Все фрагменты кода, кроме последнего, верны. А вот последняя инструкция содержит две переменные со звездочкой, что расширенным синтаксисом распаковывания последовательностей не допускается.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *