Как работают области видимости в Python?
- Что такое правило LEGB?
- Чем отличаются global и nonlocal?
- Откуда берётся UnboundLocalError?
Имя ищется по цепочке LEGB: Local → Enclosing → Global → Built-in.
- Присваивание внутри функции делает имя локальным для всей функции
global— писать в переменную модуля,nonlocal— в переменную объемлющей функции
А ещё Циклы и if своей области не создают — только функции, классы, модули, comprehension
Подробно
Когда Python встречает имя, он ищет его последовательно:
- Local — локальные имена текущей функции;
- Enclosing — локальные имена объемлющих функций (для вложенных);
- Global — имена модуля;
- Built-in — встроенные:
len,print,Exception.
Важно, когда решается «локальное ли имя»: при компиляции функции. Если в теле функции где-либо есть присваивание имени, оно локальное во всей функции. Поэтому код ниже падает с UnboundLocalError: x += 1 — это присваивание, значит x локальная, а читается она до того, как получила значение.
global x говорит, что x — имя модуля; nonlocal x — что это имя ближайшей объемлющей функции. Злоупотреблять global не стоит: состояние лучше передавать явно.
Блоки if, for, while, with новой области не создают: переменная цикла доступна после цикла. А генераторы списков и выражения-генераторы (comprehension) имеют свою область — их переменная наружу не утекает.
Пример
x = 10
def broken():
x += 1 # UnboundLocalError
def fixed():
global x
x += 1
for i in range(3):
pass
print(i) # 2 — цикл не создаёт область
[j for j in range(3)]
# print(j) # NameError — у comprehension своя областьЧто хотят услышать
- Порядок поиска LEGB.
- Правило «присваивание делает имя локальным» и UnboundLocalError.
- Разница между
globalиnonlocal. - Что блоки не создают области видимости.
Частые ошибки
- Думать, что
ifилиforсоздают свою область, как в C или Java. - Объяснять UnboundLocalError «порядком строк», не упоминая правило присваивания.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Имя ищется по цепочке Local → Global → Built-in, а nonlocal даёт запись в переменные модуля
- ✗Цикл for создаёт свою область видимости
- ✗Присваивание внутри функции меняет глобальную переменную без объявлений
- ✓Поиск имени: Local → Enclosing → Global → Built-in; запись во внешние — через global и nonlocal
Что спросят дальше
- Что такое замыкание? Junior
Разбор темы
- Функции — аргументы, области видимости, замыкания и декораторы
Как передаются аргументы, *args и **kwargs, LEGB, ловушка изменяемого значения по умолчанию, замыкания и позднее связывание, декораторы и functools.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.