Область видимости: 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.
В следующем уроке познакомимся с лямбда-функциями — компактным способом записать простую функцию в одну строку.