Области видимости; инструкции global, nonlocal
Область видимости — часть программы, в пределах которой переменная остаётся связанной с объектом, то есть позволяет посредством себя обратиться к нему.
Например, в приведённом ниже коде:
def add(x, y): return x + y a = 1 b = 2 print(add(a, b))
Где существуют x и y? Ответ: только внутри функции add. Более того, при каждом вызове функции add создаётся новая область, и в каждой такой области свои x и y.
Всего в Python четыре области видимости:
Локальная - это внутри функции (обычной или lambda)
Охватывающая (nonlocal) - особая область видимости, которая существует только для вложенных функций. Если локальная область видимости - это внутренняя функция, то объемлющая область видимости - это область видимости внешней функции. Например:
def add(a, b, c, d): def add_2(x, y); return x + y return add_2(a, b) + add_2(c, d)
для функции add_2 переменные x, y находятся в локальной области видимости, а переменные a, b, c, d - в объемлющей.
Глобальная - эта область видимости Python содержит все имена переменных, которые вы определяете на верхнем уровне программы или модуля. Имена в этой области видимы отовсюду в вашем коде.
Встроенная область видимости - это специальная область видимости Python, которая создается при запуске программы. Эта область содержит такие имена, как ключевые слова, встроенные функции, исключения и другие атрибуты, которые встроены в Python. Имена в этой области видимости Python также доступны отовсюду в вашем коде.
Когда мы пишем variable = "some value" внутри функции, то переменная variable будет находиться в области видимости этой функции (а также вложенных функций).
Однако, когда мы пишем внутри функции do_something(variable), то variable ищется во всех областях видимости, по порядку от первой до четвёртой.
В этих двух пунктах может случиться коллизия. Например, мы напишем
counter = 0 def increment_counter(): counter = counter + 1 return counter print(increment_counter())
counter = counter + 1 до присваивания будет искать переменную counter во всех областях видимости, и найдёт её в глобальной области; а во время присваивания вроде как нужно создать в локальной области.
Python без специальных инструкций так делать не позволяет:
counter = counter + 1
^^^^^^^
UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value
Для разрешения таких случаев есть специальные инструкции:
- global говорит интерпретатору, что переменную необходимо создавать и искать в глобальной области видимости
- nonlocal говорит, что переменную необходимо создавать и искать в нелокальной области видимости
Код выше можно переписать так:
counter = 0 def increment_counter(): global counter counter = counter + 1 return counter print(increment_counter())