Пространство имен и область видимости в 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.