Python: области видимости
Если «Python: области видимости» вызывает ступор — это нормально: тема собрана из простых идей. Покажем их по порядку: теория, пример, разбор задания и типичные ошибки.
Что такое области видимости в Python
Иногда программа выглядит совсем простой, но переменная внезапно «не находится», а изменение значения внутри функции не влияет на результат снаружи. Такие ошибки особенно неприятны на контрольной: код почти правильный, но Python использует не ту переменную или сообщает об ошибке. Разобравшись с областями видимости, ты поймёшь, где создаётся имя, откуда его можно прочитать и почему функция не всегда меняет внешние данные.
Область видимости — это часть программы, в которой имя переменной доступно. В Python обычно выделяют четыре уровня: локальный внутри функции, объемлющий во внешней функции, глобальный в модуле и встроенный, где находятся готовые имена вроде print и len. Их часто обозначают правилом LEGB: Local, Enclosing, Global, Built-in.
Важно различать имя и объект. Переменная — это имя, связанное со значением. В разных областях могут существовать одинаковые имена, но они будут ссылаться на разные объекты. Именно поэтому одинаковое слово number внутри и вне функции не обязательно означает одну и ту же переменную.
Как Python ищет переменную
Когда интерпретатор встречает имя, он ищет его последовательно. Сначала проверяется текущая функция, затем внешняя функция, если она есть, потом уровень модуля и в конце встроенные имена. Если подходящего имени нет нигде, появляется NameError.
Локальная переменная создаётся при присваивании внутри функции. Она существует только во время выполнения этой функции. После завершения вызова доступиться к ней из основной программы нельзя. Параметры функции тоже являются локальными переменными.
Глобальная переменная создаётся на уровне модуля, то есть вне функций. Функция может прочитать её, если внутри нет локального имени с таким же названием. Но попытка присвоить новое значение без специального указания создаёт локальную переменную.
message = "Вне функции"
def show():
print(message)
show() → Вне функции
В этом примере функция только читает глобальное имя. Для чтения ключевое слово global не требуется.
Присваивание и ключевые слова global и nonlocal
Рассмотрим важное правило: если внутри функции встречается присваивание имени, Python считает это имя локальным во всей функции. Поэтому код ниже завершится ошибкой ещё до вывода значения: интерпретатор решит, что count локальная, но прочитать её пытаются раньше присваивания.
\( count = 3 \)
def increase():
print(count)
\( count = count + 1 \)
Чтобы изменить глобальную переменную, применяют global. Для переменной из внешней, но не глобальной функции используют nonlocal. Однако чрезмерное изменение внешних данных усложняет программу: функция начинает зависеть от состояния, спрятанного в другом месте.
\( score = 10 \)
def add_point():
global score
\( score = score + 1 \)
add_point()
print(score) → 11
Чаще безопаснее передать значение аргументом и вернуть новый результат. Так код легче проверять и тестировать.
Если сомневаешься, нарисуй границы функций и подпиши, где создаётся каждое имя. Затем отдельно отметь чтение и изменение переменной. Такой разбор почти всегда показывает причину ошибки.
Разобранный пример с вложенной функцией
Теперь разберём пример полностью. Внешняя функция создаёт локальную переменную base, а вложенная функция использует её и получает параметр bonus. Вызов make_result(4) запускает внешний код, затем внутренний. Имя base не найдено локально во внутренней функции, поэтому Python ищет его на объемлющем уровне.
def make_result(bonus):
\( base = 6 \)
def calculate():
\( return base + bonus \)
return calculate()
\( answer = make_result(4) \)
print(answer) → 10
Шаг 1: вызывается make_result, параметр bonus получает 4. Шаг 2: создаётся локальное имя base со значением 6. Шаг 3: создаётся вложенная функция calculate. Шаг 4: при её запуске Python находит base во внешней функции, а bonus также доступен из объёмлющей области. Шаг 5: возвращается сумма 10.
Если бы внутри calculate мы написали base = 8, это стало бы локальным присваиванием. Чтобы изменить внешнюю переменную, понадобилось бы слово nonlocal.
| Уровень | Где создаётся | Как используется |
|---|---|---|
| Local | Внутри функции | Доступен только в ней |
| Enclosing | Во внешней функции | Доступен вложенным функциям |
| Global | В модуле | Доступен функциям для чтения |
| Built-in | Встроенный Python | print, len и другие |
Типичные ошибки и практика
Первая ошибка — считать, что функция автоматически меняет внешнюю переменную. Присваивание внутри функции создаёт локальное имя, если не указано иное. Вторая — использовать глобальные переменные для обмена данными между множеством функций. Это затрудняет поиск места, где значение изменилось.
Третья ошибка связана с изменяемыми объектами. Список, созданный снаружи, можно изменить внутри функции через append без global, потому что меняется сам объект, а не связь имени с новым объектом. Но запись items = [] уже создаёт локальное имя.
\( items = [1, 2] \)
def add_item():
items.append(3)
add_item()
print(items) → [1, 2, 3]
Проверяй себя вопросами: где создано имя, где выполняется код, есть ли присваивание внутри функции и не совпадает ли имя с встроенной функцией. Для бесплатной практики можно открыть личный кабинет и решить несколько коротких задач по областям видимости.
Не называй переменную list, sum или input: ты перекроешь встроенное имя и позже можешь получить неожиданную ошибку.
Что запомнить
Область видимости определяет, где доступно имя. Python ищет переменные по порядку LEGB: локальная, объемлющая, глобальная, встроенная область. Чтение внешней переменной обычно разрешено, но присваивание внутри функции делает имя локальным. global позволяет изменить имя модуля, а nonlocal — имя внешней функции.
На практике отдавай предпочтение аргументам и возвращаемым значениям: так зависимости функции видны сразу. Если возник NameError или значение не изменилось, сначала проверь границы функций и присваивания.
Следующий шаг — зарегистрируйся и реши 5 заданий бесплатно в личном кабинете. После этого попробуй объяснить правило LEGB своими словами и написать пример с вложенной функцией.
Что такое область видимости?
Это часть программы, где Python может найти конкретное имя переменной или функции. Например, локальное имя доступно внутри функции, а глобальное создано на уровне модуля.
Почему присваивание внутри функции создаёт локальную переменную?
Так устроено правило Python: наличие присваивания сообщает интерпретатору, что имя относится к текущей функции. Для изменения внешнего имени нужны global или nonlocal.
Чем отличаются global и nonlocal?
global обращается к имени на уровне модуля, а nonlocal — к имени внешней функции во вложенной функции.
Как закрепить тему после разбора?
Реши пять небольших задач: определи результат программы, найди область каждого имени и исправь один пример с NameError. Затем создай собственную пару вложенных функций и объясни порядок поиска LEGB.
Проверь себя на реальных заданиях
После такого разбора решите 5–7 заданий подряд — и тема ваша. Тренажёр Просто Урок подберёт их автоматически и объяснит ошибки по шагам. Бесплатно.