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

codechick

СodeСhick.io - простой и эффективный способ изучения программирования.

2024 ©