Понимание нюансов пространств имен и областей действия Python часто бывает полезным для принятия мудрых решений при написании продвинутого Python. Python - настолько дружелюбный язык, что позволяет легко нарушать правила и при этом достигать наших целей. Но иногда правила, нарушенные в прошлом, могут вернуться и укусить нас в будущем невообразимым образом.

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

Пространство имен - это отображение между именами переменных и объектами. Существует 3 основных типа пространств имен:

  • Пространства имен __main__ и builtins - здесь находятся все встроенные имена, и это пространство имен создается при запуске интерпретатора.
  • Global пространство имен - здесь находятся все имена, объявленные с помощью ключевого слова global.
  • Локальное пространство имен - сюда относятся локальные переменные, объявленные в модуле или функции.

Сфера

Область действия - это текстовая область программы Python, в которой непосредственно доступно пространство имен. Любая прямая ссылка на имя в области видимости напрямую просматривается в пространстве имен, к которому имеет доступ.

Поиск по имени

Когда выполняется код Python, поиск имени происходит в этом порядке

  1. Локально - поиск имени в локальном пространстве имен функции.
  2. Включение - если его нет в локальном пространстве имен, найдите его в области действия функции включения.
  3. Global - если его там нет, выполните поиск в глобальном пространстве имен текущего модуля.
  4. Main - если его нет в global, выполните поиск во встроенных пространствах имен и __main__.

нелокальные и глобальные ключевые слова

В Python есть два специальных ключевых слова

  • global - Любая переменная с глобальным префиксом связывает эту переменную с глобальным пространством имен
  • нелокальный - любая переменная с нелокальным префиксом привязывает переменную к области видимости, которая включает локальную область видимости, но внутреннюю и глобальную. Или, другими словами, размах между глобальным и локальным.
def scope_test():
    def do_local():
        spam = "local spam" ## Local scope

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam" ## Enclosing scope

    def do_global():
        global spam
        spam = "global spam" ## Global scope

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

Выход выглядит так:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

Как видно из примера, «локальный спам» понятен. «Нелокальный спам» привязан к области действия метода def scope_test (). Таким образом, даже после вызова do_global () мы по-прежнему видим «нелокальный спам», потому что выполнение останавливается на шаге 3 (из алгоритма поиска по имени выше) после того, как он находит именной спам.