Область видимости: local, global, nonlocal

Область видимости: local, global, nonlocal

Когда вы создаёте переменную внутри функции, она существует только пока функция выполняется. После возврата переменная исчезает. Это не случайность — это область видимости (scope). Понимание области видимости помогает избежать неочевидных ошибок и писать предсказуемый код.

Локальная область (local scope)

Переменная, созданная внутри функции — локальная. Она недоступна снаружи:

def calculate():
    result = 42    # локальная переменная
    return result

calculate()
# print(result)  # NameError: name 'result' is not defined

Каждый вызов функции создаёт свою независимую область видимости. Переменные разных вызовов не пересекаются:

def show():
    x = 10
    print(x)

show()   # 10
show()   # 10 — новый вызов, новая x

Глобальная область (global scope)

Переменные на уровне модуля (вне функций) — глобальные. Их можно читать из функции:

greeting = "Привет"   # глобальная переменная

def say_hello(name):
    print(f"{greeting}, {name}!")   # читаем глобальную

say_hello("Алиса")   # Привет, Алиса!

Но изменить глобальную переменную внутри функции напрямую — нельзя. Python создаст новую локальную с тем же именем:

counter = 0

def increment():
    counter = counter + 1   # UnboundLocalError!
    # Python видит присваивание counter = ... и считает counter локальной,
    # но она ещё не определена в этом вызове

Ключевое слово global

Чтобы функция могла изменить глобальную переменную, нужно явно объявить это через global:

counter = 0

def increment():
    global counter
    counter += 1

increment()
increment()
print(counter)   # 2

global counter сообщает Python: «переменная counter в этой функции — та же самая, что снаружи, не создавай новую».

Использовать global следует осторожно. Функции, изменяющие глобальное состояние, труднее тестировать и отлаживать — каждый вызов может менять видимую другим функциям переменную. Лучший вариант — передавать значение как аргумент и возвращать новое:

# Хуже: изменяем глобальное состояние
total = 0
def add_to_total(x):
    global total
    total += x

# Лучше: функция без побочных эффектов
def add(current, x):
    return current + x

total = 0
total = add(total, 5)
total = add(total, 3)

Правило LEGB

Python ищет переменную по цепочке: Local → Enclosing → Global → Built-in.

  • Local — переменные текущей функции
  • Enclosing — переменные объемлющей (внешней) функции
  • Global — переменные модуля
  • Built-in — встроенные (len, print, range...)

Первое найденное значение используется. Вот почему именование list = [1, 2] «затеняет» встроенную функцию list.

Ключевое слово nonlocal

nonlocal нужен, когда вложенная функция хочет изменить переменную объемлющей функции (не глобальную):

def make_counter():
    count = 0

    def increment():
        nonlocal count   # изменяем переменную объемлющей функции
        count += 1
        return count

    return increment

counter = make_counter()
print(counter())   # 1
print(counter())   # 2
print(counter())   # 3

Каждый вызов counter() увеличивает count, которое «живёт» в объемлющей функции make_counter. Это паттерн замыкания (closure) — функция запоминает переменные из своего окружения. О замыканиях подробнее — в продвинутых темах; пока достаточно понимать, что nonlocal позволяет изменять переменные внешней (но не глобальной) функции.

Проверь себя

Что выведет следующий код?

x = "глобальная"

def outer():
    x = "внешняя"
    def inner():
        x = "внутренняя"
        print(x)
    inner()
    print(x)

outer()
print(x)

Каждая функция создаёт собственную x. Вывод:

внутренняя
внешняя
глобальная

Итог

  • Переменные внутри функции — локальные; снаружи не видны.
  • Из функции можно читать глобальные переменные.
  • Чтобы изменить глобальную переменную — используйте global имя.
  • Чтобы изменить переменную объемлющей функции — используйте nonlocal имя.
  • Предпочитайте передавать данные через аргументы и return, а не через global.
  • Python ищет переменную по цепочке: Local → Enclosing → Global → Built-in.

В следующем уроке познакомимся с лямбда-функциями — компактным способом записать простую функцию в одну строку.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике