Пространство имен и область видимости в Python
В этом уроке вы узнаете о пространстве имен, привязке имени к объекту и области видимости переменной в Python.
Что такое имя
Последняя строка «Дзен Питона» гласит: «Пространства имен — отличная штука! Давайте будем использовать ее чаще!». Что же это за загадочные пространства имен? Давайте сначала узнаем, что такое имя.
Примечание. Если не читали «Дзен Питона», введите
import thisв интерпретаторе.
Например, когда мы присваиваем a = 2, 2 — это объект, хранящийся в памяти, а a — это имя, с которым мы его связываем. Мы можем получить адрес объекта в ОЗУ с помощью встроенной функции id (). Давайте посмотрим, как ей пользоваться. Имя (оно же идентификатор) — это просто название, данное объекту. В Python всё — объекты, а имя — это способ доступа к объекту.
# Примечание: вы можете получить другие значения id.
a = 2
print('id(2) =', id(2))
print('id(a) =', id(a))
Вывод:
id(2) = 9302208
id(a) = 9302208
Здесь оба аргумента ссылаются на 2, поэтому у них одинаковый id. Давайте сделаем задачу немного интереснее.
# Примечание: вы можете получить другие значения id.
a = 2
print('id(a) =', id(a))
a = a+1
print('id(a) =', id(a))
print('id(3) =', id(3))
b = 2
print('id(b) =', id(b))
print('id(2) =', id(2))
Вывод:
id(a) = 9302208
id(a) = 9302240
id(3) = 9302240
id(b) = 9302208
id(2) = 9302208
Что происходит в программе выше? Давайте рассмотрим это на диаграмме:

Сначала создается объект 2 и с ним связывается имя a. Когда мы обновляем значение a = a + 1, создается новый объект 3, и теперь уже a ссылается на этот объект.
Обратите внимание, что id (a) и id (3) выдают одинаковые значения.
Кроме того, когда выполняется строка b = 2, новое имя b связывается с предыдущим объектом 2.
Это эффективное решение, поскольку Python не нужно создавать дубликаты объектов. Такая динамическая привязка имен и делает Python мощным. Также имя может относиться к любому типу объекта.
>>> a = 5
>>> a = 'Привет, мир!'
>>> a = [1,2,3]
Все эти привязки действительны, и a будет ссылаться на три различных типа объектов на разных стадиях. Функции тоже являются объектами, поэтому имя может ссылаться и на них.
def printHello():
print("Привет!")
a = printHello
a()
Вывод:
Привет!
Как видите, имя a может ссылаться на функцию и мы можем вызывать ее, используя это имя.
Что такое пространство имен
Теперь, когда мы понимаем, что такое имена, мы можем перейти к понятию пространства имен.
Проще говоря, пространство имен — это набор имен.
В Python вы можете представить себе пространство имен в виде отображения каждого имени, которое вы определили, на соответствующие объекты.
В определенный момент времени могут сосуществовать несколько пространств имен, и все они будут полностью изолированы.
Пространство имен, содержащее все встроенные имена, создается при запуске интерпретатора Python и существует, пока интерпретатор не завершит работу.
По этой причине встроенные функции, такие как id (), print () и т. д., всегда доступны из любой части программы.
Каждый модуль создает свое собственное глобальное пространство имен.
Все разные пространства имен изолированы. Следовательно, одно и то же имя, которое используется в разных модулях, не вызывает противоречий.
В модулях могут быть различные функции и классы. При вызове функции создается локальное пространство имен данной функции. Так же — с классом. Следующая диаграмма поможет лучше понять эту концепцию.

Область видимости переменных
Несмотря на то, что различные пространства имен могут быть определены одновременно, мы не сможем получить доступ ко всем из них в каждой части программы. Тут в игру вступает область видимости.
Область видимости — это часть программы, из которой можно получить доступ к пространству имен напрямую, без какого-либо префикса.
В любой момент работы программы существует как минимум три области видимости:
- область видимости текущей функции, имеющей локальные имена;
- область видимости модуля, имеющего глобальные имена;
- самая внешняя область видимости, хранящая встроенные имена.
Когда объект вызывается внутри функции, Python сначала ищет имя в локальном пространстве имен, затем в глобальном пространстве имен и, наконец, во встроенном пространстве имен.
Если внутри одной функции определена другая, то пространство имен последней будет вложено в локальное пространство первой.
Пример работы области видимости и пространства имен
def outer_function():
b = 20
def inner_function():
c = 30
a = 10
Здесь переменная a находится в глобальном пространстве имен. Переменная b находится в локальном пространстве имен outer_function (), а c находится во вложенном локальном пространстве имен inner_function ().
Когда мы находимся в inner_function (), c является для нас локальной переменной, b нелокальной, а a — глобальной. Мы можем получить доступ к значениям всех трех переменных a, b и c, однако изменять значение мы можем только у c.
Если мы попытаемся изменить значение b, в локальном пространстве имен будет создана новая переменная b, которая отличается от нелокальной версии b. То же самое происходит, когда мы изменяем значение a.
Однако, если мы объявим a как глобальную, все обращения будут направлены к глобальной a. Точно так же, если мы хотим поменять значение переменной b, она должна быть объявлена нелокальной. Следующий пример демонстрирует это.
def outer_function():
a = 20
def inner_function():
a = 30
print('a = ', a)
inner_function()
print('a = ', a)
a = 10
outer_function()
print('a = ', a)
Вывод:
a = 30
a = 20
a = 10
В этой программе три разные переменные a определены в отдельных пространствах имен. А в следующей программе не так.
def outer_function():
global a
a = 20
def inner_function():
global a
a = 30
print('a = ', a)
inner_function()
print('a = ', a)
a = 10
outer_function()
print('a = ', a)
Вывод:
a = 30
a = 30
a = 30
Здесь все обращения и объявления относятся к глобальной переменной a благодаря ключевому слову global.