Ответ
В 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, если внутри шкафа лежат другие шкафы. А то потом будешь искать, кто тебе список испоганил, а это ты сам, мудя, через другую ссылку!