Область видимости в Python
Изучите область видимости Python и правило LEGB: локальная, вложенная, глобальная и встроенная области с примерами и ключевыми словами global/nonlocal.
Понимание области видимости в Python
Область видимости определяет, где имя переменной доступно и как долго оно существует. Каждое имя, которое вы создаёте — переменная, функция, класс — принадлежит ровно одной области видимости. Когда Python встречает имя, он ищет его по областям видимости в строгом порядке, пока не найдёт это имя или не выбросит NameError.
На этой странице рассматриваются:
- Четыре уровня области видимости и правило поиска LEGB
- Ключевые слова
globalиnonlocal - Распространённые ошибки: затенение имён,
UnboundLocalErrorи утечка имён - Как проверить области видимости во время выполнения
Правило LEGB
Python разрешает имена в четырёх слоях, поиск ведётся от самого внутреннего к самому внешнему:
| Уровень | Расшифровка | Что содержит |
|---|---|---|
| L | Local (Локальный) | Имена, определённые внутри текущей функции |
| E | Enclosing (Вложенный) | Имена в любой внешней (охватывающей) функции, для вложенных функций |
| G | Global (Глобальный) | Имена, определённые на верхнем уровне текущего модуля |
| B | Built-in (Встроенный) | Имена, предустановленные Python — print, len, range, type и др. |
Python останавливается на первом совпадении. Если совпадение не найдено ни в одном слое, выбрасывается NameError.
Локальная область видимости
Имя является локальным, если оно присваивается внутри функции. Оно создаётся при вызове функции и уничтожается при её возврате. Локальные имена недоступны за пределами функции.
def greet():
message = "Hello, World!" # local variable
print(message) # accessible here
greet()
# Output: Hello, World!
print(message) # NameError: name 'message' is not definedПочему локальная область видимости важна
Локальная область видимости позволяет использовать простые, описательные имена, такие как total, result или i, внутри каждой функции, не допуская конфликтов ни между ними, ни с кодом на уровне модуля.
def calculate_area(radius):
pi = 3.14159 # local to this function
area = pi * radius ** 2
return area
def calculate_volume(radius, height):
pi = 3.14159 # completely separate local 'pi'
volume = pi * radius ** 2 * height
return volume
print(calculate_area(5)) # 78.53975
print(calculate_volume(5, 10)) # 785.3975Обе функции используют pi независимо. Никакого конфликта нет.
Вложенная область видимости
Когда функция определена внутри другой функции, внутренняя функция может читать имена из внешней (охватывающей) функции. Это и есть E в LEGB.
def outer():
color = "blue" # enclosing variable
def inner():
print(color) # reads from enclosing scope
inner()
outer()
# Output: blueВнутренняя функция может читать color без каких-либо специальных ключевых слов, поскольку Python автоматически поднимается к охватывающей области видимости.
Изменение переменной во вложенной области видимости с помощью nonlocal
Чтение переменной из охватывающей области происходит автоматически, но присвоение ей требует ключевого слова nonlocal. Без него Python расценивает присвоение как создание новой локальной переменной, а не изменение охватывающей.
def make_counter():
count = 0 # enclosing variable
def increment():
nonlocal count # declare intent to modify the enclosing 'count'
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3Каждый вызов counter() изменяет одну и ту же переменную count. Этот паттерн лежит в основе замыканий — подробнее см. Python Closures.
Глобальная область видимости
Имена, определённые на верхнем уровне модуля (за пределами любой функции), являются глобальными. Они доступны из любого места того же модуля, включая внутренности функций.
language = "Python" # global variable
def display_language():
print(language) # reads global without any keyword
display_language()
# Output: PythonИзменение глобальной переменной с помощью global
Читать глобальную переменную из функции можно без каких-либо ключевых слов. Но если вы хотите присвоить ей значение, сначала необходимо объявить её с помощью global:
total = 0 # global variable
def add_to_total(n):
global total # declare intent to modify the global
total += n
add_to_total(5)
add_to_total(3)
print(total) # 8Без global total строка total += n выбросит UnboundLocalError, потому что Python будет считать total локальной переменной, которой ещё не было присвоено значение.
Подробнее о глобальных переменных см. Python Global Variables.
Когда следует избегать global
Активное использование global усложняет тестирование кода и понимание его логики. Предпочтительнее возвращать значения из функций и передавать данные в виде аргументов. Используйте global только для подлинного состояния уровня модуля — флагов конфигурации, счётчиков или кешей — и делайте это редко.
Встроенная область видимости
Встроенная область видимости содержит имена, которые Python предоставляет автоматически. Они доступны в каждом модуле без каких-либо импортов.
Распространённые встроенные имена: print, len, range, type, int, str, list, dict, set, tuple, open, input, max, min, sum, sorted, enumerate, zip и map.
Не затеняйте встроенные имена
Поскольку встроенная область видимости проверяется последней, любое локальное или глобальное имя с таким же написанием будет её затенять. Это распространённая ошибка:
# Bad: shadows the built-in 'list'
list = [1, 2, 3]
print(type(list)) # <class 'list'> — still works here
new = list([4, 5]) # TypeError: 'list' object is not callableУдалите затеняющее имя, чтобы восстановить доступ к встроенному:
del list # remove the local/global shadowing name
new = list([4, 5]) # works again: [4, 5]Встроенный модуль доступен как builtins, если когда-либо потребуется обратиться к нему явно:
import builtins
print(builtins.len([1, 2, 3])) # 3Распространённые ошибки
UnboundLocalError
Самая частая ошибка, связанная с областью видимости в Python, — это чтение имени до его присвоения внутри функции, когда в той же функции есть присвоение этому имени:
x = 10
def bad_func():
print(x) # UnboundLocalError! Python sees x = 20 below
x = 20 # this makes 'x' local for the whole function
bad_func()Python во время компиляции определяет, что x является локальной переменной (поскольку ей присваивается значение в функции). Попытка прочитать её до присвоения вызывает UnboundLocalError: local variable 'x' referenced before assignment.
Исправить это можно, объявив global x либо не присваивая значение x внутри функции.
Затенение переменных
Локальная переменная с тем же именем, что и глобальная, неявно затеняет глобальную. Обычно это делается намеренно, но это может вызывать трудноуловимые ошибки, когда вы ожидаете читать глобальную переменную:
x = 10 # global
def my_func():
x = 20 # local — shadows the global
print(x) # 20, not 10
my_func()
print(x) # 10 — global unchangedПроверка области видимости во время выполнения
Python предоставляет содержимое текущей области видимости через две встроенные функции.
locals() возвращает словарь текущей локальной области видимости (или пространство имён уровня модуля, если вызвана на верхнем уровне):
def show_locals():
a = 1
b = "hello"
print(locals()) # {'a': 1, 'b': 'hello'}
show_locals()globals() возвращает словарь глобального (уровня модуля) пространства имён:
language = "Python"
print("language" in globals()) # TrueЭти функции полезны для отладки и интроспекции, но не следует использовать их для динамического управления переменными в продакшн-коде.
Область видимости и функции
Функции в Python являются объектами и сами по себе представляют собой имена, живущие в некоторой области видимости. Функция, определённая на верхнем уровне модуля, является глобальной; функция, определённая внутри другой функции, является локальной для охватывающей функции.
def outer():
def helper(): # helper is local to outer
return 42
return helper()
print(outer()) # 42
# helper() # NameError: helper is not defined hereО том, как определяются функции, см. Python Functions, а об анонимных функциях, которые также подчиняются правилу LEGB, — Python Lambda.
Краткий справочник
| Ключевое слово | Действие |
|---|---|
| (нет) | Чтение из ближайшей охватывающей области по правилу LEGB |
global x | Указывает текущей функции, что x ссылается на имя уровня модуля |
nonlocal x | Указывает текущей функции, что x ссылается на имя в ближайшей охватывающей функции |