← Назад к вопросам

В чем разница между локальной переменной и именами?

2.3 Middle🔥 191 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Локальная переменная vs Имена (Names/Bindings)

Это базовый, но важный концепт о том, как Python управляет переменными и памятью. "Имена" — это ключевое слово для понимания Python.

Основная идея

В Python нет "переменных" в классическом смысле. Есть имена (names), которые привязаны (bound) к объектам в памяти.

# Это НЕ создаёт переменную с значением 10
# Это создаёт имя 'x', которое привязано к объекту int(10)
x = 10

print(id(x))       # Адрес объекта в памяти
print(type(x))     # <class 'int'>
print(id(10))      # Тот же адрес! Потому что это ОДИН объект

Локальные переменные (Local Variables)

Локальные переменные — это имена, определённые в локальной области видимости (функция, класс):

def my_function():
    x = 10  # Локальное имя
    y = 20  # Локальное имя
    
    def inner():
        z = 30  # Локальное имя во вложенной функции
        return x + y + z  # Может обращаться к x, y (enclosure) и z (local)
    
    return inner()

my_function()
print(x)  # NameError: x не определена в глобальной области

Что такое "имена" (Names/Bindings)?

Имя — это ссылка на объект, живущий в памяти. Одно имя может быть переназначено, несколько имён могут указывать на один объект:

# Одно имя, несколько объектов (последовательно)
x = 10
print(id(x))  # Адрес объекта int(10)

x = "hello"   # Имя x теперь указывает на другой объект
print(id(x))  # Адрес объекта str("hello")

# Несколько имён, один объект
y = 10
print(id(10))    # Адрес int(10)
print(id(y))     # Тот же адрес!
print(y is x)    # False (y указывает на 10, x на "hello")

# Несколько имён на один объект
list1 = [1, 2, 3]
list2 = list1  # Оба имена указывают на ОДИН список
print(list1 is list2)  # True

list1.append(4)
print(list2)  # [1, 2, 3, 4] — список изменился везде

Область видимости (Scope)

Локальные имена ограничены областью видимости:

x = "global"  # Глобальное имя

def function1():
    x = "local"  # Локальное имя в function1
    print(x)  # "local"

def function2():
    print(x)  # "global" — нет локального x, берём из внешней области

function1()  # "local"
function2()  # "global"
print(x)     # "global"

LEGB правило (scope resolution)

Когда Python ищет имя, он проходит через области в таком порядке:

# L — Local (локальная область функции)
# E — Enclosing (внешняя область вложенной функции)
# G — Global (глобальная область модуля)
# B — Built-in (встроенные функции и типы)

global_var = "global"

def outer():
    enclosing_var = "enclosing"
    
    def inner():
        local_var = "local"
        
        # При обращении к переменной Python ищет в порядке LEGB
        print(local_var)      # L — найдёт локальную
        print(enclosing_var)  # E — найдёт в enclosing
        print(global_var)     # G — найдёт в global
        print(len)            # B — встроенная функция
    
    return inner

inner_func = outer()
inner_func()

Изменение значения в разных областях

x = 10  # Глобальное

def func1():
    x = 20  # Локальное, НЕ изменяет глобальное
    print(x)  # 20

def func2():
    global x  # Говорим Python: используем глобальное имя
    x = 30    # Изменяем глобальное
    print(x)  # 30

def func3():
    nonlocal x  # Используется в nested функциях
    x = 40     # Изменяет enclosing область

func1()
print(x)  # 10 — глобальное не изменилось

func2()
print(x)  # 30 — глобальное изменилось

# nonlocal пример
def outer():
    x = 50
    
    def inner():
        nonlocal x
        x = 60
    
    inner()
    print(x)  # 60

outer()

Изменяемые vs неизменяемые объекты

Локальные имена могут указывать на изменяемые или неизменяемые объекты:

# Неизменяемые (immutable)
x = 10       # int
x += 5       # Создаёт новый объект int(15), x указывает на него

s = "hello"
s += " world"  # Создаёт новый объект str("hello world")

# Изменяемые (mutable)
my_list = [1, 2, 3]      # Локальное имя
my_list.append(4)         # Изменяет объект, на который указывает мне
print(my_list)            # [1, 2, 3, 4]

my_list = [5, 6]          # Переназначение имени на новый объект

# Передача в функцию
def modify_list(lst):
    lst.append(99)        # Изменяет исходный объект

data = [1, 2, 3]
modify_list(data)
print(data)  # [1, 2, 3, 99]

Жизненный цикл локального имени

def example():
    # 1. Имя x создано и привязано к объекту int(10)
    x = 10
    print(locals())  # {'x': 10}
    
    # 2. Имя переназначено на другой объект
    x = 20
    print(locals())  # {'x': 20}
    
    # 3. Имя удалено
    del x
    print(locals())  # {}
    # print(x)  # NameError

example()

Практические примеры

Проблема 1: Неожиданное переиспользование имена

# ❌ Плохо
def process_data(data):
    result = []  # Локальное имя
    for i, item in enumerate(data):
        result.append(item * 2)
    
    # Переиспользуем имя для чего-то совсем другого
    result = sum(result)  # Теперь result — число, не список
    return result

# ✅ Хорошо
def process_data(data):
    doubled = [item * 2 for item in data]  # Ясное имя
    total = sum(doubled)                   # Другое имя
    return total

Проблема 2: Closure и локальные имена

# ❌ Классическая ошибка с closure
functions = []
for i in range(3):
    def func():
        return i  # Захватывает имя i, не значение
    functions.append(func)

for f in functions:
    print(f())  # 2, 2, 2 (i везде 2)

# ✅ Правильно: захвати значение
functions = []
for i in range(3):
    def make_func(val):
        def func():
            return val
        return func
    functions.append(make_func(i))

for f in functions:
    print(f())  # 0, 1, 2

# Или через default argument
functions = []
for i in range(3):
    def func(val=i):  # val получает ТЕКУЩЕЕ значение i
        return val
    functions.append(func)

for f in functions:
    print(f())  # 0, 1, 2

Проверка областей

def check_scope():
    x = 10
    y = 20
    
    # locals() — локальные имена
    print(locals())  # {'x': 10, 'y': 20, 'check_scope': <function>}
    
    # globals() — глобальные имена
    print(globals())  # Все имена на модульном уровне

check_scope()

Итоговое различие

АспектЛокальная переменнаяИмя (Binding)
Что этоОбласть видимостиСсылка на объект
Жизненный циклДо конца функцииПока существует ссылка
Может менять значениеДаДа (переназначение)
Может быть удаленоДа (del)Да (del)
Видимо в locals()ДаДа

Ключ к пониманию Python: переменные — это просто имена, указывающие на объекты. Отпусти идею о "переменной как контейнера» и поймёшь Python.

В чем разница между локальной переменной и именами? | PrepBro