Локальная переменная – это именованное хранилище данных, объявленное внутри блока/функции и доступное только в пределах области видимости этого блока. Тема объединяет три фундаментальных понятия: область видимости (scope), время жизни (lifetime) и место хранения (storage). Для ЕГЭ по информатике понимание локальных переменных критично в задачах на функции/процедуры, рекурсию, замыкания, корректную работу со счётчиками циклов, а также при анализе программ, где требуется предсказать значение переменных после выполнения фрагмента.
Область видимости (scope) – множество точек программы, в которых имя переменной доступно для использования. Для лексически-скоупируемых языков (Pascal, C/C++, Python) это лексический блок: функция, тело цикла, begin…end, отступ в Python.
Время жизни (lifetime) – интервал исполнения, когда значение переменной существует в памяти.
Место хранения (storage) – где физически лежит значение (обычно стек активаций; реже – статическая область или куча при захвате в замыкание).
Теневание (shadowing) – локальное имя «перекрывает» одноимённую переменную внешнего уровня.
Активирующая запись (activation record, кадр стека) – набор локальных переменных, параметров и служебной информации вызова функции.
Формально, для переменной x, объявленной внутри блока B, верно:
доступность: x видна, если текущая точка исполнения ∈ scope(B) и имя x не затенено именем из вложенного блока;
время жизни: [t_alloc(x), t_free(x)) ⊆ интервал исполнения B.
При вызове функции создаётся кадр стека с локальными переменными и параметрами. По завершении – кадр снимается, локальные переменные уничтожаются.
Классическая оценка памяти при рекурсии:
stack_usage = frame_size * recursion_depth
где frame_size – суммарный объём локалов и служебных полей, recursion_depth – максимальная глубина стека.
Инварианты:
Локальная переменная недоступна вне своего кадра.
Ссылки на локальные переменные «после выхода» недействительны (за исключением корректно реализованных замыканий/копий).
Правило 1 (минимальная область): объявляйте локальную переменную в максимально узком блоке, где она нужна. Это снижает риски ошибок и улучшает читаемость.
Правило 2 (полная инициализация): локальные переменные должны быть инициализированы до первого чтения. В C/C++ это требование безопасности; в Python/Паскале чтение неинициализированной переменной – логическая ошибка.
Правило 3 (безопасность имён): избегайте повторного использования имен внешних переменных (теневание). Если оно неизбежно, документируйте намерение.
Пример (Python, показ лексической области и инициализации):
def f(a):
# локальная переменная s видна только в f
s = 0
for x in a:
s += x
return s
Передача по значению создаёт локальную копию параметра (в C++ примитивы). Изменения копии не влияют на аргумент.
Передача по ссылке/указателю разрешает функции менять внешние данные (C++ T&, T*; Pascal var-параметры).
Python (модель ссылок): имена – ссылки на объекты; присваивание внутри функции делает имя локальным, если не объявлен global/nonlocal. Мутирование изменяемого объекта через локальную ссылку влияет на внешний объект, переназначение имени – нет.
Примеры (ограничения области в Python):
x = 10
def g():
# x здесь локальна, так как присваивание создаёт локальное имя
x = 5
return x
# Чтобы изменить внешнюю x:
def h():
global x
x = 5
Локальная константа – имя, значение которого не меняется после инициализации (Pascal const, C++ const, Python – идиоматично ИМЯ_ЗАГЛАВНЫМИ).
Правило 4 (минимизация мутабельности): объявляйте локалы константными, когда это возможно – упрощает доказательство корректности и снижает число ошибок.

Статический локал хранит значение между вызовами функции, но остаётся невидимым вне её области.
В C++: static int counter = 0; внутри функции.
В Python аналог – хранить состояние в атрибуте функции или использовать замыкание/объект.
Правило 5 (реентерабельность): статический локал нарушает реентерабельность и потокобезопасность, если изменяется без синхронизации.
Замыкания и захват локальных переменных
Замыкание – функция, которая «захватывает» переменные из лексического окружения. Важны два варианта:
Захват по значению (копия) – безопасен по времени жизни.
Захват по ссылке – требует гарантий, что захваченная переменная живёт дольше замыкания.
Python (LEGB и nonlocal):
def make_adder(k):
s = 0 # локальная переменная внешней функции
def add(x):
nonlocal s
s += x
return x + k, s
return add
Здесь s – локальная для make_adder, но доступна add через nonlocal. Без nonlocal присваивание создало бы новую локальную s внутри add.
Правило 6 (escape-анализ): не допускайте «утечки» ссылок на локальные переменные вне времени их жизни (актуально для языков без безопасных замыканий).
Локальные переменные, рекурсия и оценка ресурсов
Для рекурсивной функции со средним размером кадра frame_size и глубиной D (макс.):
stack_usage = frame_size * D
Если локальные массивы велики, используйте динамическое выделение в куче (или статическую память) и аккуратно освобождайте ресурсы. Для ЕГЭ важно уметь оценить пределы: где возможен переполнение стека и как преобразовать решение в итеративное.
Локальные переменные по определению приватны для потока (в кадре стека конкретного потока). Опасность возникает при:
доступе к общим статическим/глобальным объектам из функции;
захвате общей структуры в замыкание.
Правило 7 (потокобезопасность): изменяемые локалы безопасны, пока они не ссылаются на общий объект. При наличии общих объектов – используйте синхронизацию.
Чтение до инициализации (C/C++ неопределённое поведение; в Python – UnboundLocalError).
Теневание имён (переменная внешнего уровня «исчезает» в блоке).
Зависание на «устаревшей» ссылке после выхода из функции (указатели/ссылки в C/C++).
Неправильный global/nonlocal в Python – неожиданное изменение внешнего состояния.
Статические локалы + рекурсия/параллелизм – некорректные результаты.
Мини-шпаргалка правил
Объявляйте локальные переменные как можно ближе к месту использования.
Инициализируйте локалы немедленно при объявлении.
Предпочитайте локальные константы и иммутабельные структуры.
Избегайте теневания и глобальных эффектов без нужды.
Для рекурсии/глубоких вызовов оценивайте stack_usage формулой
stack_usage = frame_size * recursion_depth.
В Python: помните про LEGB и ключевые слова global, nonlocal.
В заданиях ЕГЭ регулярно встречаются:
определение результата фрагмента с локальными/глобальными переменными;
анализ рекурсивных функций (в том числе вычисление количества вызовов и значения счётчиков);
задачи на функции-генераторы и замыкания (Python) с nonlocal;
перевод псевдокода с блочной структурой в выбранный язык (PascalABC.NET, C++, Python) с сохранением области видимости.
Упражнение 1. Область видимости и теневание (Python)
Дан код:
x = 7
def f(a):
x = a + 1
def g(b):
return x + b
return g(3)
res1 = f(2)
def h():
global x
x = x + 5
h()
res2 = x
а) Укажите значения res1 и res2.
б) Объясните, какие x (глобальная/локальная) используются в каждой точке.
в) Перепишите f так, чтобы внутренняя функция модифицировала «внешнюю локальную» x (используйте nonlocal).
Упражнение 2. Рекурсия и локальные счетчики (Pascal/C++)
Пусть рекурсивная функция вычисляет сумму цифр числа и в каждом кадре создаёт локальный массив из 16 целых.
а) Выразите stack_usage через frame_size и глубину рекурсии D.
б) Оцените максимальную глубину для числа до 10^18.
в) Предложите итеративный вариант без рекурсии и сравните использование памяти.
Упражнение 3. Замыкание и nonlocal (Python)
Напишите функцию make_counter(start), возвращающую две функции: inc() (увеличивает счётчик и возвращает его) и reset() (сбрасывает к start).
а) Реализуйте корректный захват локальной переменной.
б) Покажите, почему без nonlocal поведение будет неверным.
в) Объясните, где и как живёт захваченная локальная переменная.
Упражнение 4. Статический локал и реентерабельность (C++/псевдокод)
Дана функция:
int f() {
static int s = 0;
s += 1;
return s;
}
а) Объясните, почему f не является реентерабельной.
б) Предложите потокобезопасный вариант (без глобальных переменных).
в) Предложите эквивалент на Python без статического локала (используйте объект или замыкание).
Упражнение 5. Анализ LEGB и ошибки UnboundLocalError (Python)
Дан код:
y = 10
def p():
print(y) # A
def q():
print(y) # B
y = 5 # C
def r():
y = 2
def s():
print(y)
s()
p()
а) Укажите, что выведет p() и почему.
б) Объясните, почему q() вызывает UnboundLocalError и на какой строке.
в) Исправьте q() двумя способами: с global y и без глобальной модификации (переименуйте локальную).
Локальные переменные – базовый инструмент дисциплины программирования: они изолируют состояние, упрощают доказуемость корректности и уменьшают риски ошибок. Освоение правил области видимости, времени жизни и места хранения, умение работать с замыканиями и аккуратно оценивать стек при рекурсии напрямую повышают качество решений на ЕГЭ и формируют профессиональные навыки разработки.