Глобальная и локальная видимость переменных в Python

Раздел: Основы Python -> Переменные и области видимости

Глобальные и локальные переменные: основные принципы

В Python область видимости переменной определяет, где в коде эта переменная доступна. Переменные, созданные вне функций, считаются глобальными. Внутри функции переменные по умолчанию локальны, если только не указано иное.

Наиболее эффективный способ изменить глобальную переменную из функции - использовать инструкцию global. Без неё присваивание внутри функции создаст новую локальную переменную, скрывающую глобальную.

x = 10
def change():
    global x
    x = 20
change()
print(x)  # 20

Python global local (глобальные и локальные переменные в python)

Пояснение: строка global x объявляет, что x относится к глобальной области видимости. Последующее присваивание меняет глобальную переменную.

Типичная ошибка: попытка изменить глобальную переменную без global вызывает UnboundLocalError.

y = 5
def f():
    y = y + 1  # Ошибка: y считается локальной до присваивания
f()

Решение: добавить global y внутри функции.

Цель использования: когда необходимо модифицировать глобальное состояние из нескольких функций, например счётчики вызовов или общие настройки.

Как изменить глобальную переменную, не используя global?

Можно передать значение как аргумент и вернуть новое значение. Это более функциональный подход, избегающий побочных эффектов.

x = 10
def change(val):
    return val + 10
x = change(x)
print(x)  # 20

Проблема: если нужно изменить сразу несколько глобальных переменных, такой код становится громоздким. Также теряется прямое влияние на глобальное состояние, что может быть неудобно для простых сценариев.

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

Как работать с глобальными переменными во вложенных функциях?

Для вложенных функций (функция внутри функции) применяется инструкция nonlocal. Она позволяет изменять переменную из внешней, но не глобальной области.

def outer():
    x = 10
    def inner():
        nonlocal x
        x = 20
    inner()
    print(x)  # 20
outer()

Ошибка: использование nonlocal для переменной, которой нет во внешней функции, вызывает SyntaxError.

Применение: замыкания, декораторы, счётчики вызовов внутри фабрик функций.

Как изменить глобальный изменяемый объект (список, словарь) без global?

Если не переназначать саму переменную, а только изменять её содержимое (методами append, pop, присвоением по индексу), то global не требуется. Объект остаётся глобальным.

my_list = [1, 2, 3]
def add_item():
    my_list.append(4)
add_item()
print(my_list)  # [1, 2, 3, 4]

Ложное ощущение безопасности: если внутри функции выполнить my_list = [5], то создастся локальная переменная, а глобальный список не изменится. Это частая ошибка новичков.

Когда уместно: когда объект уже существует и необходимо только мутировать его, например очередь задач.

Как получить доступ ко всем глобальным переменным программно?

Функция globals() возвращает словарь глобальных переменных. Можно читать и изменять их динамически.

a = 100
def show_globals():
    for name, value in globals().items():
        if not name.startswith('__'):
            print(name, value)
show_globals()  # a 100

Не рекомендуется для продакшена: злоупотребление globals() усложняет чтение кода и может привести к неожиданным побочным эффектам.

Случаи использования: метапрограммирование, отладка, фреймворки с динамической загрузкой конфигураций.

Расширенные примеры с пояснениями

Пример 1: Изменение глобальной числовой переменной с global

Пример
counter = 0
def increment():
    global counter
    counter += 1
increment()
increment()
print(counter)  # 2
2

Объяснение: global counter позволяет изменять глобальный счётчик. Без этой строки возникла бы ошибка UnboundLocalError.

Пример 2: Использование nonlocal во вложенных функциях (замыкание-счётчик)

Пример
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c1 = make_counter()
print(c1())  # 1
print(c1())  # 2
c2 = make_counter()
print(c2())  # 1
1
2
1

Объяснение: nonlocal count дает вложенной функции доступ к переменной count из внешней функции make_counter. Каждый вызов make_counter создаёт собственное замыкание.

Пример 3: Изменение элементов глобального списка без global

Пример
data = [10, 20, 30]
def update_data():
    data[0] = 99
update_data()
print(data)  # [99, 20, 30]
[99, 20, 30]

Объяснение: присваивание по индексу data[0] = 99 не пересоздаёт локальную переменную, а модифицирует существующий глобальный объект.

Пример 4: Создание локальной переменной, скрывающей глобальную (теневая переменная)

Пример
x = 'глобальная'
def func():
    x = 'локальная'
    print(x)  # локальная
func()
print(x)      # глобальная
локальная
глобальная

Объяснение: внутри функции присваивание x = ... создаёт новую локальную переменную, глобальная не затрагивается.

Пример 5: UnboundLocalError и его исправление

Пример
y = 5
def bad():
    print(y)  # компилятор считает y локальным из-за последующего присваивания
    y = 10
bad()
UnboundLocalError: local variable 'y' referenced before assignment

Решение:

Пример
def good():
    global y
    print(y)
    y = 10
good()  # 5
5

Объяснение: интерпретатор видит присваивание внутри функции и решает, что y локальна. Инструкция global y отменяет это.

Пример 6: Использование globals() для динамического изменения глобальных переменных

Пример
config = {'port': 8080}
def set_config(key, value):
    if key in globals():
        globals()[key] = value
    else:
        print('Нет такой глобальной переменной')
set_config('config', {'port': 9000})
print(config)  # {'port': 9000}
{'port': 9000}

Объяснение: globals() возвращает словарь, который можно изменять. Однако это снижает читаемость, и лучше использовать явные присваивания.

Пример 7: Передача глобальной переменной как аргумент для избежания global

Пример
name = 'Анна'
def greet(n):
    return f'Привет, {n}!'
print(greet(name))  # Привет, Анна!
Привет, Анна!

Объяснение: функция не изменяет глобальное состояние, а лишь использует переданное значение. Это предпочтительный способ для чистых функций.

Пример 8: Комбинация global и изменяемых объектов (списки)

Пример
items = []
def add_item(new_item):
    global items
    items.append(new_item)
add_item('молоко')
add_item('хлеб')
print(items)  # ['молоко', 'хлеб']
['молоко', 'хлеб']

Объяснение: global items обязательно, если вы хотите переназначить саму переменную (например, items = []). Но если переназначения не происходит, global не требуется. В данном случае append не переназначает переменную, но global всё равно указан избыточно для наглядности.

Глобальные и локальные переменные в Python - comments

En
Python global local (python)