Первые имена и значения
Правильная мысленная модель переменной в Python — не коробка с данными, а имя, указывающее на значение.
Мы уже создавали имена вроде name в предыдущих разделах —
настало время разобрать, что это на самом деле означает.
Не «коробка с данными»
Частая, но не совсем точная метафора: «переменная — это коробка, в которую кладут значение». Она сбивает с толку в Python, потому что подразумевает, будто у каждого имени своя отдельная ячейка памяти. На самом деле правильнее думать иначе:
Имя — это, скорее, стрелка, указывающая на значение. Присваивание
city = "Warsaw" не «кладёт» строку внутрь city
— оно заставляет имя city указывать на объект-строку
"Warsaw", который существует сам по себе.
Создание и чтение имени
city = "Warsaw"
print(city)
Части этой строки:
city— имя (переменная);=— оператор присваивания: «пусть имя слева указывает на значение справа»;"Warsaw"— значение (объект).
Несколько имён — один объект
Поскольку имя — это просто указатель, у одного и того же объекта может быть несколько имён одновременно. Возьмём пример:
score = 100
best_score = score
print(score)
print(best_score)
Здесь два имени — score и
best_score — но один объект, на который оба
указывают:
Переприсваивание не меняет старое имя
Продолжим тот же пример дальше:
score = 100
best_score = score
score = 120
print(score) # 120
print(best_score) # всё ещё 100
Строка score = 120 — это переприсваивание
(rebinding): имя score начинает указывать на другой объект.
Существующий объект 100 при этом никак не меняется —
best_score по-прежнему указывает на него:
Это важная идея, к которой мы ещё не раз вернёмся — при разговоре о неизменяемости чисел и строк (глава 4), о списках и их отличии от чисел, о том, как один и тот же объект может быть доступен из нескольких мест, и о том, как значения передаются в функции. Пока достаточно запомнить сам принцип: переприсваивание меняет связь имени, а не объект.
Когда объект «исчезает»?
Логичный вопрос: если score больше не указывает на
100, что происходит с самим объектом 100?
Продолжим пример ещё на шаг:
best_score = 130
print(score) # 120
print(best_score) # 130
Теперь ни score, ни best_score не
указывают на объект 100 — у него не осталось ни одной связи:
Объект 100 стал недостижимым (unreachable) —
до него нельзя «дотянуться» ни через одно имя в программе. Именно в этот момент, а не раньше,
Python может освободить память, которую он занимал.
best_score указывал на 100 даже после того, как score переприсвоили). Объект становится кандидатом на удаление только тогда, когда ни одной связи с ним не остаётся.Сборщик мусора: автоматическое управление памятью
Вам, как правило, никогда не придётся вручную «освобождать» память в Python. За этим следит сборщик мусора (garbage collector, GC) — часть самого Python, которая освобождает память недостижимых объектов автоматически.
Что происходит глубже: подсчёт ссылок
Это необязательный, более глубокий взгляд — можно спокойно пропустить его при первом чтении и вернуться позже.
В CPython (реализация Python, которой мы пользуемся) у каждого объекта есть счётчик: сколько ссылок на него сейчас существует. Пройдём наш же пример ещё раз, но уже с этим счётчиком:
score = 100 # объект 100: ссылок = 1
best_score = score # объект 100: ссылок = 2
score = 120 # объект 100: ссылок = 1 (score теперь указывает на 120)
best_score = 130 # объект 100: ссылок = 0 (недостижим)
Для обычных, не входящих в циклическую ссылку объектов в CPython момент, когда счётчик достигает нуля, обычно совпадает с моментом освобождения памяти — почти сразу, без задержки. Это удобное, практичное поведение, но не гарантия, зафиксированная языком Python в целом — другие реализации Python (например, PyPy) освобождают память по другим правилам.
У подсчёта ссылок есть одна принципиальная сложность — циклические ссылки:
A ──→ B
↑ │
└──────┘
Представьте два объекта, каждый из которых ссылается на другой. Даже если ни одно имя в программе больше не указывает ни на A, ни на B, они всё ещё ссылаются друг на друга — и счётчик ссылок каждого из них не опускается до нуля. Поэтому в CPython, кроме подсчёта ссылок, есть отдельный циклический сборщик мусора, который периодически ищет именно такие недостижимые снаружи циклы и освобождает их.
gc мы ещё вернёмся позже в курсе, когда появятся структуры данных, которые реально могут образовывать циклы (например, объекты, ссылающиеся друг на друга). Сейчас достаточно знать, что такая ситуация существует и у Python есть механизм для неё.Маленькая заметка про del
Команда del удаляет не объект, а конкретную связь
(имя):
x = 100
y = x
del x
print(y) # 100 — объект никуда не делся
del x убирает имя x из
пространства имён — но НЕ означает «удали объект 100, что бы ни случилось». Поскольку
y по-прежнему указывает на 100,
объект остаётся полностью доступным через y.
Пространство имён
Пока программа работает, Python хранит список всех созданных имён и того, на что каждое из них сейчас указывает, — это называется пространством имён (namespace). Диаграммы выше как раз и показывают срез такого пространства имён в разные моменты выполнения программы.
Обращение к ещё не созданному имени
Если обратиться к имени раньше, чем оно было создано присваиванием, Python не может догадаться, что вы имеете в виду — и сообщает об ошибке:
print(favourite_city)
favourite_city = "Warsaw"
NameError: name 'favourite_city' is not defined
Подробно про ошибки и то, как читать такие сообщения, — в разделе 3.13.