<MyRusakov.ru />

Профессиональная Web-разработка. Дизайн, код и автоматизация

Профессиональная Web-разработка. Дизайн, код и автоматизация

Это очень подробный курс из разряда "всё включено". Разбираются следующие темы: HTML, CSS, SCSS, JavaScript, PHP, SQL, Laravel, Nginx, PostCSS, npm, Vite, Vitest, Composer, PHPUnit, Prettier, Stylelint, ESLint, Pint, Larastan, Git, Agile, Scrum, Docker, Supervisord, Figma, Stitch AI, Confluence, Jira.

Рассчитан и на новичков, и на тех, кто уже знаком с основами, но хочет освоить полный цикл разработки.

Помимо самой теории, Вы увидите пример создания Web-проекта на 20 000 строк кода: от идеи и документации на Confluence через планирование на Jira, fullstack-разработку до деплоя на VPS.

Помимо уроков, курс содержит упражнения для закрепления знаний и финальное тестирование. А ещё Вы получите 5 полноценных Бонусных курсов: «GitLab под ключ», «Вёрстка сайта с нуля 2.0», «JavaScript с Нуля до Гуру 2.0», «PHP и MySQL с Нуля до Гуру 3.0» и «Laravel от А до Я».

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Области видимости в Python: LEGB, global и nonlocal — понятное руководство с примерами

Области видимости в Python: LEGB, global и nonlocal — понятное руководство с примерами

Если ваш код «видит» не ту переменную или падает с UnboundLocalError, почти наверняка проблема в областях видимости. В этой статье мы разберём правило LEGB, а также ключевые слова global и nonlocal в Python — на практичных примерах, с советами и типичными ошибками новичков.

LEGB: как Python ищет переменные

LEGB — это порядок поиска имени переменной:

  • Local — локальная область (внутри текущей функции)
  • Enclosing — область внешних функций (для вложенных функций)
  • Global — глобальная область модуля
  • Builtins — встроенные имена Python (len, sum и др.)

Посмотрим на простой пример теневого перекрытия имён:

x = 'global'

def outer():
    x = 'enclosing'
    def inner():
        x = 'local'
        print(x)  # local
    inner()
    print(x)      # enclosing

outer()
print(x)          # global

Python всегда берёт самое ближайшее определение по правилу LEGB.

global в Python: когда нужен и когда нет

Ключевое слово global говорит интерпретатору: «я собираюсь переназначать имя из глобальной области». Без этого Python посчитает имя локальным и может выдать UnboundLocalError.

x = 10

def bad_inc():
    print('Перед инкрементом:', x)  # Попытка прочитать локальное x до присваивания
    x = x + 1                       # UnboundLocalError: local variable 'x' referenced before assignment
    return x

# bad_inc()

def good_inc():
    global x
    x = x + 1
    return x

print(good_inc())  # 11

Важно: global нужен только при переприсваивании имени. Если вы мутируете глобальный изменяемый объект (список, словарь), global не требуется:

nums = [1, 2]

def add_three():
    nums.append(3)  # Мутация, работает без global

def reset_wrong():
    nums = []       # Переприсваивание: создаётся локальное nums, глобальное не тронуты

def reset_ok():
    global nums
    nums = []       # Явно переприсваиваем глобальное имя

add_three()
print(nums)  # [1, 2, 3]
reset_wrong()
print(nums)  # [1, 2, 3] — не сбросился!
reset_ok()
print(nums)  # []

Стоит ли использовать global?

В продакшене — редко. Глобальные изменяют состояние «изнутри», усложняя тестирование и сопровождение. Предпочтительнее передавать значения параметрами и возвращать результат:

def inc(value):
    return value + 1

x = 10
x = inc(x)

Если нужно хранить состояние — инкапсулируйте его в объект:

class Counter:
    def __init__(self, start=0):
        self.value = start
    def inc(self, step=1):
        self.value += step
        return self.value

c = Counter()
print(c.inc(), c.inc())  # 1 2

nonlocal: управление переменной внешней функции

nonlocal нужен, когда у нас есть вложенные функции и мы хотим менять переменную не глобального, а внешнего локального уровня (enclosing). Без nonlocal возникнет UnboundLocalError, как и с global-сценарием.

def outer():
    x = 0
    def inner_bad():
        x += 1              # UnboundLocalError: local variable 'x' referenced before assignment
        return x
    # return inner_bad

# outer()()

def outer_fix():
    x = 0
    def inner():
        nonlocal x          # объявляем, что x — из enclosing-области, не локальная
        x += 1
        return x
    return inner

counter = outer_fix()
print(counter(), counter(), counter())  # 1 2 3

Классический паттерн с nonlocal — «функция‑счётчик» (замыкание):

def make_counter(start=0, step=1):
    value = start
    def inc():
        nonlocal value
        value += step
        return value
    return inc

c1 = make_counter()
c2 = make_counter(100, 10)
print(c1(), c1(), c1())      # 1 2 3
print(c2(), c2())            # 110 120

Замыкания и «позднее связывание»

Частая ловушка при создании функций в цикле — все они «видят» последнее значение счётчика. Решение — зафиксировать значение аргументом по умолчанию:

funcs = []
for i in range(3):
    def f(i=i):  # фиксируем текущее i в значении по умолчанию
        return i
    funcs.append(f)

print([fn() for fn in funcs])  # [0, 1, 2]

Частые ошибки и как их избегать

  • UnboundLocalError: вы присваиваете переменной внутри функции, значит она локальная; чтение до присваивания запрещено. Лечится global, nonlocal или грамотным рефакторингом (передать параметр, вернуть результат).
  • Затенение встроенных имён: не называйте переменные как len, list, sum — вы потеряете доступ к встроенной функции.
len = 10
# print(len([1, 2]))  # TypeError: 'int' object is not callable
del len                # вернули доступ к встроенной len
print(len([1, 2]))     # 2
  • Глобальные «магические» константы: если нужны действительно глобальные значения — делайте их КОНСТАНТАМИ В ВЕРХНЕМ РЕГИСТРЕ и не меняйте (например, API_URL).
  • Сложность тестирования: функции с побочными эффектами и глобальным состоянием сложнее мокать и покрывать тестами. Делайте зависимости явными (DI через параметры).

Чеклист лучших практик

  • Избегайте global — предпочитайте параметры и возврат значений.
  • Для состояния используйте объекты (классы) или замыкания с nonlocal.
  • Не затеняйте встроенные имена и не переиспользуйте «говорящие» идентификаторы.
  • Пишите маленькие, чистые функции без скрытых зависимостей — их легко тестировать и переиспользовать.
  • Если всё же нужен глобальный реестр или кеш — инкапсулируйте доступ через функции/классы, а не меняйте переменные напрямую.

Итоги

Понимание LEGB и грамотное использование global/nonlocal избавят от трудноуловимых багов и сделают код чище. Начните с отказа от неявных глобальных состояний, а затем применяйте замыкания или объекты там, где нужен контролируемый стейт.

Хотите быстро и системно прокачать Python с практикой и домашками? Посмотрите программу и первые уроки: Открыть программу курса «Программирование на Python с Нуля до Гуру» — отличный путь от базовых тем до уверенного уровня.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.