Что такое ссылка на объект в Python и как она работает?

Ответ

В Python переменная — это ссылка (reference) на объект в памяти, а не сам объект. Присваивание (=) создает новую ссылку на существующий объект, а не копирует его.

Ключевое поведение:

  • Неизменяемые объекты (immutable): int, float, str, tuple. При «изменении» создается новый объект, и ссылка перенаправляется на него.
  • Изменяемые объекты (mutable): list, dict, set. Изменение объекта через одну ссылку видно через все другие ссылки на тот же объект.

Пример с изменяемым объектом (list):

a = [1, 2, 3]  # Создается список, `a` ссылается на него
b = a          # `b` теперь ссылается на ТОТ ЖЕ объект списка
b.append(4)    # Изменяем объект через ссылку `b`
print(a)       # [1, 2, 3, 4] — изменение видно через `a`
print(a is b)  # True — это один и тот же объект в памяти
print(id(a) == id(b))  # True — идентификаторы совпадают

Пример с неизменяемым объектом (int):

x = 10  # `x` ссылается на объект `10`
y = x   # `y` ссылается на тот же объект `10`
y = y + 5  # Создается новый объект `15`, `y` теперь ссылается на него
print(x)   # 10 — `x` по-прежнему ссылается на `10`
print(x is y)  # False — это разные объекты

Практический совет: Для создания независимой копии изменяемого объекта используйте copy() для поверхностного копирования или deepcopy() из модуля copy для рекурсивного копирования вложенных структур.

Ответ 18+ 🔞

Э, слушай, давай про ссылки в питоне, а то народ путается, как слепые котята в помойном ведре. Вот представь: переменная — это не коробка, куда ты кладёшь объект, а бирочка, бумажка с номерком, которая висит на объекте в памяти. Бирочка, блядь, а не сейф!

Вот ты пишешь a = [1, 2, 3]. Ты создал список — это объект в памяти, типа шкаф. И повесил на него бирочку a. Потом пишешь b = a. Ты что сделал? Ты не создал новый шкаф! Ты взял вторую бирочку b и повесил её на тот же самый, ёпта, шкаф! Теперь у одного шкафа две бирки.

И вот ты через бирочку b открываешь шкаф и суёшь туда четвёрку: b.append(4). Потом подходишь к бирочке a, открываешь — а там, сука, уже четыре предмета! Потому что это один и тот же шкаф! a is b вернёт True, иди проверь, пиздец как логично.

a = [1, 2, 3]
b = a
b.append(4)
print(a)       # [1, 2, 3, 4] — охуеть, да? Всё через одну дырку лезет!
print(a is b)  # True — один хуй, один объект.

А теперь смотри на неизменяемые штуки, типа чисел или строк. Это как бетонные блоки, их не переделаешь. x = 10 — повесил бирочку x на блок «10». y = x — повесил бирочку y на тот же блок. Всё пока то же самое.

Но потом ты пытаешься его «изменить»: y = y + 5. А блок-то бетонный, его не изменишь! Что происходит? Создаётся новый, отдельный, блядь, бетонный блок «15». И бирочка y срывается со старого блока и вешается на новый! А бирочка x так и болтается на старом блоке «10». Поэтому x остался 10, а x is y — уже False, разные объекты.

x = 10
y = x
y = y + 5
print(x)   # 10 — сидит себе, как сыч на суку.
print(x is y)  # False — уже разные истории.

Так вот, практический совет, чтобы не обосраться: если тебе нужна именно копия шкафа (списка или словаря), а не вторая бирка на него, используй copy() для простого копирования или deepcopy() из модуля copy, если внутри шкафа лежат другие шкафы. А то потом будешь искать, кто тебе список испоганил, а это ты сам, мудя, через другую ссылку!