Ответ
Правило LEGB описывает порядок, в котором интерпретатор Python ищет переменные. Это акроним, который расшифровывается как:
-
L (Local) — Локальная область видимости. Переменные, определенные внутри текущей функции. Поиск начинается здесь.
-
E (Enclosing) — Область видимости замыкающих функций. Переменные во внешних функциях, если текущая функция вложена в другую. Поиск идет от ближайшей внешней функции к самой дальней.
-
G (Global) — Глобальная область видимости. Переменные, определенные на верхнем уровне модуля или объявленные с помощью ключевого слова
global. -
B (Built-in) — Встроенная область видимости. Предопределенные в Python имена:
len,str,print,Exceptionи т.д. Это последняя область, где производится поиск.
Пример, демонстрирующий все уровни:
# G: Global scope
x = "global"
def outer_func():
# E: Enclosing scope
x = "enclosing"
def inner_func():
# L: Local scope
x = "local"
print(f"Внутри inner_func: {x}") # Находит 'local'
# len - пример из Built-in scope
print(f"Длина строки: {len(x)}")
inner_func()
print(f"Внутри outer_func: {x}") # Находит 'enclosing'
outer_func()
print(f"На глобальном уровне: {x}") # Находит 'global'
# Вывод:
# Внутри inner_func: local
# Длина строки: 5
# Внутри outer_func: enclosing
# На глобальном уровне: global
Ключевые слова global и nonlocal
По умолчанию Python позволяет только читать переменные из внешних областей видимости. Для их изменения используются специальные ключевые слова:
global x: Указывает, что внутри функции мы хотим изменить переменнуюxиз глобальной (G) области видимости.nonlocal y: Указывает, что мы хотим изменить переменнуюyиз ближайшей замыкающей (E) области видимости (не глобальной).
Ответ 18+ 🔞
А, ну это же про то, как питон ищет, где у него какая переменная лежит! Правило LEGB, блядь. Расшифровывается просто, как ёбушки-воробушки.
- L (Local) — Локальная, то есть прямо в этой функции, где ты сейчас сидишь. Тут всё начинается, питон сначала тут шарится.
- E (Enclosing) — Область вложенных функций, если они есть. То есть смотрит в ту функцию, внутри которой твоя текущая сидит, как в матрёшке.
- G (Global) — Глобальная, то есть на самом верхнем уровне файла, где все импорты и объявления.
- B (Built-in) — Встроенная, последний причал. Тут
print,lenи прочая родная хуйня, которая из коробки.
А теперь смотри, как это всё в деле выглядит, на примере, который даже работает, ёпта:
# G: Глобальная область — тут мы все в одном котле
x = "global"
def outer_func():
# E: Область замыкания — тут уже своя кухня
x = "enclosing"
def inner_func():
# L: Локальная область — тут полный суверенитет
x = "local"
print(f"Внутри inner_func: {x}") # Найдёт 'local', естественно
# А вот len — это уже из Built-in, последняя инстанция
print(f"Длина строки: {len(x)}")
inner_func()
print(f"Внутри outer_func: {x}") # Найдёт своё 'enclosing'
outer_func()
print(f"На глобальном уровне: {x}") # А тут как было 'global', так и осталось
# Вывод:
# Внутри inner_func: local
# Длина строки: 5
# Внутри outer_func: enclosing
# На глобальном уровне: global
Всё логично, да? Каждая функция в своей берлоге свою переменную x нашла. Но есть нюанс, блядь! По умолчанию питон изнутри функции может только посмотреть на внешнюю переменную. А вот взять и поменять её — хуй там! Он новую локальную создаст и будет доволен.
Поэтому, если тебе реально надо изнутри функции нагло переписать глобальную переменную или переменную во внешней функции — нужны волшебные слова.
global x— это как крикнуть: «Эй, народ, я сейчас буду мутить с тойx, которая на самом верху, в глобальной области! Не мешайте!».nonlocal y— это потише: «Так, ребят,yя буду менять не здесь, а в той функции, которая меня обнимает. Свою локальную создавать не буду».
Вот и вся магия, а то некоторые думают, что тут какая-то ебейшая космология. Всё на поверхности, просто порядок поиска, как в бюрократической конторе — от своего кабинета до самого главного начальника.