Предполагается, что вы уже умеете писать простые программы на Python и знаете базовый синтаксис (if, for, функции, списки). Здесь мы разбираем не как пользоваться языком, а почему он работает именно так.

За последние несколько статей мы много раз говорили одну и ту же фразу.

Имя начинает ссылаться на объект.

Например:

x = 10

или

numbers = [1, 2, 3]

Мы уже знаем, что переменная не является “ячейкой памяти”, внутри которой лежит значение.

Создаётся объект.

А имя начинает ссылаться на него.

Но теперь возникает новый вопрос.

Где вообще хранится само имя?


Попробуйте выполнить такой код.

name = "Python"

print(name)

Почему Python вообще знает, что такое name?

Ведь мы нигде не говорили:

“Сохрани эту переменную вот здесь.”

Получается, что где-то существует место, в котором Python хранит все известные ему имена.

Такое место действительно существует.

Оно называется пространством имён (namespace).


Можно представить пространство имён как обычную таблицу.

В левом столбце находятся имена.

В правом - ссылки на объекты.

Например, после выполнения такого кода:

x = 10
text = "Hello"
numbers = [1, 2, 3]

пространство имён можно представить так:

Имя          Объект
----------------------------
x        ───► 10
text     ───► "Hello"
numbers  ───► [1, 2, 3]

Обратите внимание.

В таблице нет самих объектов.

Там находятся только ссылки на них.

Именно поэтому несколько имён могут ссылаться на один объект.

Например:

a = [1, 2]
b = a

Тогда таблица выглядит так:

Имя      Объект
-------------------------
a   ─┐
     ├────► [1, 2]
b   ─┘

Мы уже встречались с такой ситуацией раньше.

Теперь становится понятно, где Python хранит эту информацию.


Когда выполняется присваивание

x = 20

Python не ищет какую-то специальную “переменную”.

Он просто изменяет запись в пространстве имён.

Если раньше таблица выглядела так:

x ───► 10

то после присваивания становится такой:

x ───► 20

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


Теперь вспомним оператор del.

Что происходит здесь?

del x

Мы уже знаем ответ.

Объект может продолжать существовать.

Удаляется не он.

Удаляется запись из пространства имён.

Было:

x ───► 10

Стало:

(записи больше нет)

После этого Python больше не знает никакого имени x.

Именно поэтому попытка написать

print(x)

заканчивается ошибкой NameError.

Не потому, что исчез объект.

А потому, что исчезла запись в пространстве имён.


Может возникнуть ещё один интересный вопрос.

Если пространство имён - это просто таблица имён, то сколько таких таблиц существует?

Одна на всю программу?

Или несколько?

Оказывается, пространство имён далеко не одно.

Например, переменные внутри функции не смешиваются с переменными, объявленными снаружи.

Это означает, что Python создаёт отдельные пространства имён для разных частей программы.

Именно поэтому можно написать такой код:

x = 10

def func():
    x = 20
    print(x)

func()

print(x)

Результат будет таким:

20
10

Хотя имя x использовалось дважды.

Почему так происходит?

Потому что это две разные записи в двух разных пространствах имён.


Именно пространства имён позволяют Python одновременно использовать одинаковые имена в разных местах программы, не создавая путаницы.

Пока что нам достаточно запомнить одну простую мысль.

Имя не существует само по себе.

Оно всегда находится внутри некоторого пространства имён.

Именно там Python хранит связь между именами и объектами.


В следующей статье мы сделаем ещё один шаг вперёд.

Мы уже знаем, что пространств имён несколько.

Но как Python понимает, в каком из них искать имя?

Почему внутри функции сначала находится локальная переменная, а уже потом - глобальная?

И что происходит, если одно и то же имя существует сразу в нескольких местах?

Именно это мы и разберём дальше.