UpPetto

This is a real course generated by UpPetto — unedited.

AI-generated. Two models wrote it, a third checked every risky claim against sources, a fourth re-checked.

Create my own course

Имена как привязки к объектам: почему '=' — это не memcpy

core предсказать, изменится ли объект через второе имя, ссылающееся на тот же список/словарь, без запуска кода

В C переменная — это именованная область памяти фиксированного размера и типа, выделенная компилятором на стеке или явно в куче. int x = 5; означает: зарезервировать несколько байт, положить туда битовое представление числа 5, и всё последующее x = ... — это memcpy-подобная запись новых байт в ту же самую ячейку. int y = x; выделяет новую ячейку и копирует в неё содержимое x: после этого x и y — два независимых хранилища. Присваивание в C — операция копирования значения в фиксированное место.

В Python имя не является ячейкой памяти. Имя — это привязка (запись в пространстве имён, по сути ключ в словаре), которая ссылается на объект, живущий в куче интерпретатора. x = 5 не резервирует «ячейку x» — оно создаёт (или находит) объект 5 и делает так, чтобы имя x указывало на него. Следующее x = "hello" не «перезаписывает x другим типом» — оно просто переставляет привязку имени на другой объект. Ни размер, ни тип имени никогда не были фиксированы, потому что у имени вообще нет ни размера, ни типа — тип есть у объекта.

Отсюда прямое следствие, которого нет в C: два разных имени могут ссылаться на один и тот же объект. Это называется aliasing. Ключевой вопрос, который нужно научиться задавать вместо привычного «скопировалось ли значение» — изменяемый (mutable) объект или неизменяемый (immutable)?

  • Если объект изменяемый (list, dict, set, большинство пользовательских классов) — мутация через любое из имён видна через все остальные имена, ссылающиеся на тот же объект.
  • Если объект неизменяемый (int, float, str, tuple, frozenset) — у него нет операций, меняющих его «изнутри». Любая операция, похожая на изменение (b = b + 1), создаёт новый объект и перепривязывает имя к нему.

Функция id() возвращает идентификатор объекта (в CPython он связан с адресом объекта в памяти) и позволяет проверить, ссылаются ли два имени на один объект.

graph LR
    subgraph "C: имя = ячейка"
    X["x: int, адрес 0x100"] -->|memcpy| V1["байты: 5"]
    end
    subgraph "Python: имя = привязка"
    A["a"] --> O["объект int(5)"]
    B["b"] --> O
    end
В C имя жёстко связано с ячейкой памяти; в Python имя — привязка, и несколько имён могут ссылаться на один объект

Разобранный пример

a = [1, 2, 3]
b = a          # b и a — два имени одного и того же объекта list
b.append(4)
print(a)       # что здесь?

Рассуждение по-сишному подсказывает: «b = a — это копия структуры, значит a не тронут». Это неверно. [1, 2, 3] — объект в куче. a и b — два имени, привязанные к этому же объекту. b.append(4) мутирует объект in place, не создавая новый, поэтому изменение видно через оба имени: a тоже станет [1, 2, 3, 4]. Проверить это можно через id(a) == id(b) — идентификаторы совпадают.

Настоящая независимая копия требует явного действия:

c = a.copy()   # новый объект-список с тем же содержимым
c.append(5)
print(a)       # [1, 2, 3, 4] — оригинал не тронут

Сравните с неизменяемым случаем:

a = 1000
b = a
b = b + 1
print(a)   # 1000 — не изменилось

Тут b + 1 создаёт новый объект int(1001) и перепривязывает b к нему. a продолжает ссылаться на старый объект 1000. Мутации не было — была перепривязка одного из двух имён.

Попробуй сейчас

Не запуская код, определите, что выведет каждый print:

d1 = {"count": 0}
d2 = d1
d2["count"] = 5

s1 = "hi"
s2 = s1
s2 = s2 + "!"

t1 = (1, [2, 3])
t2 = t1
t2[1].append(4)

print(d1["count"])   # ?
print(s1)            # ?
print(t1)            # ?

Ожидаемый результат: 5, "hi", (1, [2, 3, 4]). Первый и третий случай — мутация общего изменяемого объекта (dict; и вложенный list внутри неизменяемого tuple — сам tuple неизменяем, но хранит ссылку на изменяемый список, и мутируется именно список). Второй случай — str неизменяем, s2 + "!" создал новый объект, s1 не тронут.

Получилось, если…

Вы разобрались, если для любой пары «имя A, имя B, ссылающихся на один объект» можете сразу сказать: изменение через B видно через A только если объект изменяемый и операция мутирует его in place (.append, [key] =, .sort()), а не создаёт новый объект и перепривязывает B. И если понимаете, зачем нужен явный .copy().

Вывод

= в Python — это привязка имени к объекту, а не копирование байт. Aliasing (несколько имён → один объект) — нормальное состояние программы, а не побочный эффект. «Увидят» ли другие имена изменение, решают два вопроса: mutable или immutable объект, и мутирует ли операция объект in place или создаёт новый.

AI-generated · source-grounded review

🛡 Fact-checked: 5 risky claims verified · 4 removed · confidence: high · figures: 2
[verified] В Python имя — привязка к объекту, а не типизированная ячейка памяти; `=` не копирует значение
База знаний прямо утверждает: имена — привязки (bindings), `=` связывает имя с объектом
[verified] Несколько имён могут ссылаться на один объект (aliasing); мутация изменяемого объекта видна через все имена
Подтверждено разделом «Объектная модель Python: всё — объект»
[softened] `int x = 5;` резервирует 4 (или 8) байта
Размер зависит от платформы, конкретика отсутствует в базе знаний — заменено на «несколько байт»
[softened] id() возвращает адрес объекта в памяти
База знаний упоминает id как идентификатор; связь с адресом ограничена оговоркой «в CPython»
[verified] Неизменяемые типы: int, float, str, tuple, frozenset; изменяемые: list, dict, set
База знаний относит tuple/int к immutable, list/dict к mutable
[verified] Диаграмма mermaid: в C имя → ячейка (memcpy), в Python два имени → один объект int(5)
Соответствует описанию различия C-переменной и Python-привязки в базе знаний; убраны конкретные id
[verified] SVG: до `b = b + 1` имена a и b → int:10; после — a → int:10, b → новый int:11
Соответствует неизменяемости int и перепривязке имени, описанным в базе знаний
[removed] Из версии A убрана конкретика «4 (или 8) байта» → «несколько байт»: точный размер int зависит от платформы и не подтверждён базой знаний
[removed] Из версии A убраны конкретные значения id (`id=0x7f...`) в подписи/метке диаграммы — конкретные адреса не воспроизводимы
[removed] Утверждение про id() смягчено: «в CPython связан с адресом объекта», а не безусловное «это его адрес»
[removed] Две декоративные mermaid-диаграммы версии B (одно имя → объект; два имени → объект) удалены как не добавляющие ничего к тексту и дублирующие сохранённую диаграмму версии A

A second model re-checked this lesson's claims and corroborated 5 of 7 , and could not confirm 2 either way. This is incomplete corroboration, not a disagreement.

Key concepts: binding mutable/immutable aliasing
Tell me more 🔒 Didn't understand — explain simply 🔒 Show examples 🔒 Sources 🔒

On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Write my course

Check yourself

1. Что делает оператор `b = a`, если `a` — список?
2. После `a = 500; b = a; b = b + 1`, чему равно `a`?
3. Дан код: ```python list1 = [1, 2] list2 = list1 list2.append(3) print(list1) ``` Что будет выведено?
4. В чём фундаментальное различие между переменной в C (`int x;`) и именем в Python (`x = ...`)?
On your own course, these are marked as you answer