В чем разница между пространством имен и областью видимости в Python

Ответ

Хотя эти понятия тесно связаны, они описывают разные аспекты работы с переменными.

  • Пространство имен (Namespace) — это структура данных, которая хранит имена (переменные, функции) и связывает их с объектами. По сути, это словарь {'имя': объект}. В Python существует несколько пространств имен: встроенное (built-in), глобальное, локальное.

  • Область видимости (Scope) — это текстовая область в коде, из которой можно напрямую получить доступ к именам из определенного пространства имен. Она определяет правила, по которым Python ищет переменную в разных пространствах имен.

Ключевое правило поиска — LEGB (Local → Enclosing → Global → Built-in):

  1. L (Local) — локальная область внутри функции.
  2. E (Enclosing) — область видимости внешней функции (для вложенных функций).
  3. G (Global) — глобальная область модуля.
  4. B (Built-in) — встроенные имена Python (print, len и т.д.).

Пример:

x = 'global_x' # Имя 'x' в глобальном пространстве имен

def outer_func():
    y = 'enclosing_y' # Имя 'y' в локальном пространстве имен outer_func

    def inner_func():
        z = 'local_z' # Имя 'z' в локальном пространстве имен inner_func
        print(x) # Найдено в Global (G)
        print(y) # Найдено в Enclosing (E)
        print(z) # Найдено в Local (L)

    inner_func()

outer_func()
# print(z) # Ошибка! NameError: name 'z' is not defined в глобальной области видимости

Итог:

  • Пространство имен — это «что» (хранилище имен).
  • Область видимости — это «где» (правила доступа к этому хранилищу).

Ответ 18+ 🔞

Давай разжую эту тему так, чтобы даже твоя бабушка, если бы вдруг решила в Python податься, всё поняла. Представь, что пространство имён — это такой большой, блядь, шкаф с ящиками. В каждом ящике лежат бумажки с надписями: «х», «у», «моя_переменная», «функция_которая_ничего_не_делает». На бумажке написано имя, а на обратной стороне — адрес, где в памяти этот объект живёт, типа «а вот тебе, сука, сам объект».

Так вот, пространство имён (namespace) — это и есть сам этот ящик, контейнер, словарь, где хранятся пары «имя → объект». Их несколько видов: встроенный ящик (там print, len лежат), глобальный (для всего модуля) и локальные (внутри каждой функции свои).

А теперь область видимости (scope) — это, сука, невидимые правила твоего дома. Они тебе говорят: «Слушай сюда, дружок-пирожок. Из кухни (локальная область) ты можешь лезть в холодильник на кухне (локальный namespace), а также в общий шкаф в прихожей (глобальный namespace), и даже в кладовку со старым хламом (встроенный namespace). Но из прихожей (глобальная область) тебе, мудак, на кухню в личные ящики лезть НИЗЗЯ!».

Вот эти правила поиска — и есть LEGB, священная мантра питониста:

  1. L (Local) — ищем на кухне, в своих тапках.
  2. E (Enclosing) — если не нашли, смотрим в коридоре за стенкой (если функция вложенная).
  3. G (Global) — если и там нет, идём в общий зал, ко всем.
  4. B (Built-in) — ну а если совсем всё хуёво, лезем в фундамент дома, там всегда True, False и прочая хуйня валяется.

Смотри, как это в коде выглядит, ёпта:

x = 'global_x' # Бросил бумажку "x" в общий ящик в зале (глобальный namespace)

def outer_func():
    y = 'enclosing_y' # Бросил бумажку "y" в ящик в коридоре (локальный namespace outer_func)

    def inner_func():
        z = 'local_z' # Бросил бумажку "z" в ящик на кухне (локальный namespace inner_func)
        print(x) # Ищешь "x". На кухне нет (L). В коридоре нет (E). В зале — ОПА! Нашёл! (G)
        print(y) # Ищешь "y". На кухне нет (L). В коридоре — О, ёба, вот же! (E)
        print(z) # Ищешь "z". На кухне — да тут он, блядь, в первом ящике! (L)

    inner_func()

outer_func()
# print(z) # А вот тут, друг мой, пиздец. Ты в зале (глобальная область), а пытаешься найти "z",
          # который лежит только на кухне (в локальной области inner_func). NameError, пидорас!

Итог, коротко и на пальцах:

  • Пространство имён — это ЧТО (ящик с бумажками-ссылками).
  • Область видимости — это ГДЕ и ПО КАКИМ ПРАВИЛАМ тебе разрешено в эти ящики лазить.

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