Объясните правило LEGB для областей видимости в Python

Ответ

Правило LEGB описывает порядок, в котором интерпретатор Python ищет переменные. Это акроним, который расшифровывается как:

  1. L (Local) — Локальная область видимости. Переменные, определенные внутри текущей функции. Поиск начинается здесь.

  2. E (Enclosing) — Область видимости замыкающих функций. Переменные во внешних функциях, если текущая функция вложена в другую. Поиск идет от ближайшей внешней функции к самой дальней.

  3. G (Global) — Глобальная область видимости. Переменные, определенные на верхнем уровне модуля или объявленные с помощью ключевого слова global.

  4. 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, блядь. Расшифровывается просто, как ёбушки-воробушки.

  1. L (Local) — Локальная, то есть прямо в этой функции, где ты сейчас сидишь. Тут всё начинается, питон сначала тут шарится.
  2. E (Enclosing) — Область вложенных функций, если они есть. То есть смотрит в ту функцию, внутри которой твоя текущая сидит, как в матрёшке.
  3. G (Global) — Глобальная, то есть на самом верхнем уровне файла, где все импорты и объявления.
  4. 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 я буду менять не здесь, а в той функции, которая меня обнимает. Свою локальную создавать не буду».

Вот и вся магия, а то некоторые думают, что тут какая-то ебейшая космология. Всё на поверхности, просто порядок поиска, как в бюрократической конторе — от своего кабинета до самого главного начальника.