Представьте, что вы ищете ножницы. Сначала смотрите на своём рабочем столе (локально), потом в ящиках общей комнаты (объемлющая функцияИменованный блок кода, который можно вызывать многократно. Может принимать аргументы и возвращать результат.), затем в кладовке всей квартиры (модуль), и наконец — в магазине для всех домов (встроенные имена). Как только нашли — останавливаетесь.
Python ищет переменнуюИменованное хранилище для значения. Имя связывается со значением через присваивание: x = 5. по имени точно так же — по чёткому маршруту из четырёх уровней. Этот маршрут называется LEGB.
Правило LEGB
Встретив имя, Python ищет его по областям именно в таком порядке:
L — Local: локальные имена текущей функции.
E — Enclosing: имена объемлющей (внешней) функции, если функция вложенная.
G — Global: имена на уровне модуля (файла).
B — Built-in: встроенные имена (len, print, range…).
Поиск идёт изнутри наружу: L → E → G → B. Нашли — остановились.
▶ legb.py
Внутри inner() есть своя x, поэтому печатается local. Убери её — Python поднялся бы на уровень выше и нашёл enclosing, затем global. Каждая функция сначала смотрит «у себя».
global — менять глобальную переменную
По умолчанию присваивание внутри функции создаёт новую локальную переменную, а не меняет глобальную. Чтобы функция действительно меняла имя на уровне модуля, объявите его через global.
▶ global.py
nonlocal — менять переменную объемлющей функции
nonlocal похож на global, но указывает на переменную ближайшей внешней функции (уровень E), а не модуля. Нужен во вложенных функциях.
▶ nonlocal.py
💡Совет
Злоупотреблять global не стоит: глобальные переменные, которые меняют отовсюду, затрудняют отладку. Чаще лучше передать значение аргументом и вернуть результат через return. nonlocal же уместен для аккуратных замыканий вроде счётчика выше.
💡Совет
🔮 Предскажите вывод
Внутри функции есть присваивание n = n + 1 без объявления global. Что выведет код?
▶ predict-legb.py
Разбор. Внутри show() присваивание создаёт локальную n = 5, поэтому функция печатает 5. Глобальная n осталась 10 — второй print выведет 10. Чтобы функция изменила именно глобальную, понадобился бы global n.
⚠️ Частые ошибки новичков
Читают глобальную, но затем присваивают ей — и ловят UnboundLocalError. Если где-то в функции есть присваивание имени, Python считает его локальным во всей функции, даже до строкиТекстовое значение в кавычках: "привет". Неизменяема. По-английски string (str). присваивания.
Ставят nonlocal там, где нет объемлющей функции. Он работает только для вложенных функций; на уровне модуля нужен global.
▶ broken-unbound.py
Есть два выхода: либо объявить global total в начале функции (если вправду нужно менять глобальную), либо не присваивать total внутри, а вернуть новое значение через return. Ошибка возникает именно из-за присваивания ниже по коду.
Заданиерешение.py
Напишите функцию-фабрику make_accumulator(), которая возвращает функцию-накопитель. Каждый вызов накопителя прибавляет переданное число к внутренней сумме и возвращает текущий итог. Используйте nonlocal.
Заданиерешение.py
Есть глобальный список логов logs = []. Напишите функцию log(message), которая добавляет сообщение в этот глобальный список. Подсказка: для изменяемого списка global не обязателен (мы не присваиваем сам список, а вызываем метод), но объявить его допустимо.
❓Проверь себя
В каком порядке Python ищет имя переменной?
Что делает ключевое слово global внутри функции?
Когда используют nonlocal?
ℹ️Важно
✅ Что вы узнали
LEGB — порядок поиска имени: Local → Enclosing → Global → Built-in.
Присваивание внутри функции по умолчанию создаёт локальную переменную.
global позволяет менять переменную уровня модуля.
nonlocal — менять переменную объемлющей функции (замыкания).
Присваивание имени делает его локальным во всей функции — отсюда UnboundLocalError.
Комментарии
Загрузка…
Загрузка комментариев…