Область видимости в Python

Область видимости в Python

Вы, наверное, не раз слышали термин область видимости, когда изучали программирование. Это весьма важная тема, незнание которой может привести к достаточно запутанным ошибкам. Область видимости указывает интерпретатору, когда наименование (или переменная) видимо. Другими словами, область видимости определяет, когда и где вы можете использовать свои переменные, функции, и т.д. Если вы попытаетесь использовать что-либо, что не является в вашей области видимости, вы получите ошибку NameError.

Python содержит три разных типа области видимости:

  • Локальная область видимости
  • Глобальная область видимости
  • Нелокальная область видимости (была добавлена в Python 3)

Локальная область видимости

Локальная область видимости наиболее часто используется в Python. Когда мы создаем переменную в блоке кода, она будет разрешена при помощи ближайшей области видимости, или областей. Группирование всех этих областей известно как среда блоков кода. Другими словами, все назначения выполняются в локальной области по умолчанию. Если вам нужно что-то другое, тогда вам нужно настроить свою переменную на глобальную или нелокальную область, которые мы рассмотрим немного позже. Сейчас мы создадим простой пример, используя интерпретатор Python, в котором демонстрируется назначение локальной области видимости.

Результат

Здесь мы создаем переменную х и очень простую функцию, которая принимает два аргумента. Далее она выводит х и z. Обратите внимание на то, что мы не определили z, так что когда мы вызываем функцию, мы получаем ошибку NameError. Это происходит в связи с тем, что z не определена, или находится вне области видимости. Если вы определите z перед вызовом функции, тогда она будет найдена и ошибка NameError не возникнет. Ошибка NameError также возникает при попытке получения доступа к переменной, которая находится только внутри функции:

Переменная i определена только внутри функции, так что при запуске кода мы получаем ошибку NameError. Давайте немного модифицируем первый пример. Разместим данный код в python-файл и попытаемся его запустить:

  1. Что, по-вашему, должно произойти?
  2. Выдаст ли код цифру 10 дважды?

Нет, не выдаст. Причина в том, что мы имеем две переменные х. Переменная х внутри my_func имеет локальную область видимости функции и переопределяет переменную х вне функции. Так что когда мы вызываем функцию my_func, в выдаче мы видим 5, а не 10. Затем, когда функция возвращается, переменная х внутри функции my_func является кучей мусора и область для выдачи х срабатывает еще один раз. По этой причине последний оператор выдачи выдает именно 10. Если вы хотите кое-что поинтереснее, вы можете попытаться вывести х перед тем как назначить его в нашей функции:

Кода вы запустите этот код, вы получите ошибку:

Это происходит потому, что Python замечает, что вы назначаете х в функцию my_func позже, что и приводит к ошибке, так как х еще не определен.

> Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Открыть форум

Глобальная область видимости

Python содержит оператор global. Это ключевое слово Python. Оператор global объявляет переменную доступной для блока кода, следующим за оператором. Хотя вы и можете создать наименование, перед тем, как объявить его глобальным, я настоятельно не рекомендую этого делать. Давайте попробуем использовать глобальную область для исправления нашей ошибке из предыдущего примера:

Выдача данного кода должна быть следующей:

Объявляя х как глобальный, мы говорим Python использовать первое объявление х для нашего первого оператора вывода в функции. Далее мы даем х новое значение – а именно 5, и выводим его еще раз, перед тем как выйти из функции. Обратите внимание на то, что х становится глобальной переменной, когда мы доходим до последнего оператора вывода в конце кода, и там х все еще равен 5. Давайте смешаем глобальную и локальную область видимости и поглядим, что из этого получится:

Здесь мы назначаем с в качестве глобальной переменной. Таким образом, «с» будет выводиться и внутри и снаружи нашей функции. Мы также меняем местами значения переменных а и b в функции, чтобы показать, что мы можем переназначить их внутри функции, не меняя их вне функции. Это показывает, что переменные а и b не являются глобальными. Если вы запустите этот код, вы увидите следующую выдачу:

Я хочу обратить ваше внимание на то, что не нужно менять глобальные переменные внутри функции. Комьюнити Python объявило такую практику очень нежелательной, так как из-за этого исправление кода становится намного сложнее. Теперь, с пониманием основных принципов локальных и глобальных областей, мы можем перейти к нелокальной области non_local.

Область nonlocal

В Python 3 было добавлено новое ключевое слово под названием nonlocal. С его помощью мы можем добавлять переопределение области во внутреннюю область. Вы можете ознакомиться со всей необходимой на данный счет информацией в PEP 3104. Это наглядно демонстрируется в нескольких примерах. Один из самых простых – это создание функции, которая может увеличиваться:

Если вы попробуете запустить этот код, вы получите ошибку UnboundLocalError, так как переменная num ссылается прежде, чем она будет назначена в самой внутренней функции. Давайте добавим nonlocal в наш код:

Результат работы:

Теперь наша возрастающая функция работает именно так, как мы от нее и ожидаем. Для заметки, тип такой функции называется closure (дословно – закрытие). Такая функция является блоком кода, который «закрывает» переменные nonlocal. Суть в том, что вы можете ссылать переменные, которые определены вне вашей функции. Обычно, nonlocal позволяет вам назначать переменные во внешней области, но не в глобальной. Так что вы не можете использовать nonlocal в функции подсчета, так как в таком случае она попытается передать функцию глобальной области. Попробуйте, и получите ошибку SyntaxError незамедлительно. Вместо этого, вам нужно использовать nonlocal во вложенной функции.

Подведем итоги

В данной статье мы смогли понять то, как переменная ссылается, используя ключевые слова Python global и nonlocal. Мы узнали, где мы можем их использовать и зачем. Мы также узнали кое-что о локальной области видимости. Хорошего дня и продолжайте экспериментировать!