Глава 3 · Ваша первая программа на Python

Первые имена и значения

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

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

Не «коробка с данными»

Частая, но не совсем точная метафора: «переменная — это коробка, в которую кладут значение». Она сбивает с толку в Python, потому что подразумевает, будто у каждого имени своя отдельная ячейка памяти. На самом деле правильнее думать иначе:

city 'Warsaw'
Имя указывает на значение — а не «содержит» его

Имя — это, скорее, стрелка, указывающая на значение. Присваивание city = "Warsaw" не «кладёт» строку внутрь city — оно заставляет имя city указывать на объект-строку "Warsaw", который существует сам по себе.

Создание и чтение имени

names.py
city = "Warsaw"
print(city)

Части этой строки:

Несколько имён — один объект

Поскольку имя — это просто указатель, у одного и того же объекта может быть несколько имён одновременно. Возьмём пример:

score.py
score = 100
best_score = score
print(score)
print(best_score)

Здесь два имениscore и best_score — но один объект, на который оба указывают:

scorebest_score100
Две ссылки на один и тот же объект — а не два отдельных числа 100
Частая ошибка мышления
НЕ думайте, что Python «скопировал 100 в две переменные-коробки» — это ровно та модель, которую мы отвергли выше. На самом деле объект один, а связей (ссылок) с ним — две. Правильный термин для стрелки на диаграмме — ссылка (reference): «имя связано с объектом», а не «имя содержит значение».

Переприсваивание не меняет старое имя

Продолжим тот же пример дальше:

score2.py
score = 100
best_score = score
score = 120
print(score)       # 120
print(best_score)  # всё ещё 100

Строка score = 120 — это переприсваивание (rebinding): имя score начинает указывать на другой объект. Существующий объект 100 при этом никак не меняется — best_score по-прежнему указывает на него:

score120best_score100
После score = 120: у каждого имени теперь своя, независимая связь

Это важная идея, к которой мы ещё не раз вернёмся — при разговоре о неизменяемости чисел и строк (глава 4), о списках и их отличии от чисел, о том, как один и тот же объект может быть доступен из нескольких мест, и о том, как значения передаются в функции. Пока достаточно запомнить сам принцип: переприсваивание меняет связь имени, а не объект.

Когда объект «исчезает»?

Логичный вопрос: если score больше не указывает на 100, что происходит с самим объектом 100? Продолжим пример ещё на шаг:

score3.py
best_score = 130
print(score)       # 120
print(best_score)  # 130

Теперь ни score, ни best_score не указывают на объект 100 — у него не осталось ни одной связи:

score120best_score1301000 ссылок
100 стал недостижим — ни одно имя больше на него не указывает

Объект 100 стал недостижимым (unreachable) — до него нельзя «дотянуться» ни через одно имя в программе. Именно в этот момент, а не раньше, Python может освободить память, которую он занимал.

Так писать неточно
«Как только переменная перестаёт указывать на значение, сборщик мусора немедленно удаляет это значение» — эта формулировка вводит в заблуждение. Удаление одной связи НЕ уничтожает объект, если на него по-прежнему указывают другие имена (как best_score указывал на 100 даже после того, как score переприсвоили). Объект становится кандидатом на удаление только тогда, когда ни одной связи с ним не остаётся.

Сборщик мусора: автоматическое управление памятью

Вам, как правило, никогда не придётся вручную «освобождать» память в Python. За этим следит сборщик мусора (garbage collector, GC) — часть самого Python, которая освобождает память недостижимых объектов автоматически.

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

Что происходит глубже: подсчёт ссылок

Это необязательный, более глубокий взгляд — можно спокойно пропустить его при первом чтении и вернуться позже.

В CPython (реализация Python, которой мы пользуемся) у каждого объекта есть счётчик: сколько ссылок на него сейчас существует. Пройдём наш же пример ещё раз, но уже с этим счётчиком:

Объект 100 — счётчик ссылок
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 удаляет не объект, а конкретную связь (имя):

del_demo.py
x = 100
y = x
del x
print(y)  # 100 — объект никуда не делся

del x убирает имя x из пространства имён — но НЕ означает «удали объект 100, что бы ни случилось». Поскольку y по-прежнему указывает на 100, объект остаётся полностью доступным через y.

Пространство имён

Пока программа работает, Python хранит список всех созданных имён и того, на что каждое из них сейчас указывает, — это называется пространством имён (namespace). Диаграммы выше как раз и показывают срез такого пространства имён в разные моменты выполнения программы.

Обращение к ещё не созданному имени

Если обратиться к имени раньше, чем оно было создано присваиванием, Python не может догадаться, что вы имеете в виду — и сообщает об ошибке:

broken.py
print(favourite_city)
favourite_city = "Warsaw"
Ошибка
NameError: name 'favourite_city' is not defined

Подробно про ошибки и то, как читать такие сообщения, — в разделе 3.13.

Практика: имена и значения
Интерактивный ноутбук прямо в браузере — присваивание, чтение, NameError
Открыть практику →