Что такое ссылочная модель в Python?
Что проверяют
Понимаете ли вы, что переменная в Python это имя, привязанное к объекту, а не коробка со значением. Из этой модели следуют почти все бытовые сюрпризы: общий список у двух имён, накапливающий состояние аргумент по умолчанию, странное поведение оператора is.
Как отвечать
Любое значение это объект в куче со своим идентификатором, типом и счётчиком ссылок. Имя это запись в пространстве имён, указывающая на объект. Присваивание ничего не копирует, оно привязывает к объекту ещё одно имя.
Отсюда разница между изменением объекта и переприсваиванием имени. Изменение видят все имена, ссылающиеся на объект; переприсваивание отвязывает одно имя и оставляет остальные на прежнем объекте. Изменяемые типы: list, dict, set, обычные пользовательские классы. Неизменяемые: int, str, tuple, frozenset.
def add(items, x):
items.append(x) # видно снаружи
def rebind(items, x):
items = items + [x] # снаружи ничего не поменялосьПередача аргументов это call by sharing: в функцию попадает ссылка, переданная по значению. Память освобождает счётчик ссылок, а объекты, замкнутые в цикл ссылок, убирает отдельный сборщик из модуля gc. Оператор is сравнивает идентичность объектов, а не значения.
Где спотыкаются
Говорят «передаётся по ссылке» и тут же не могут объяснить, почему присваивание внутри функции снаружи не видно. Точная формулировка: по значению передаётся ссылка.
Ставят изменяемый объект значением аргумента по умолчанию. Он создаётся один раз при определении функции и копит состояние между вызовами; правильный приём это None в сигнатуре и создание объекта внутри тела.
Считают копией срез списка или вызов copy у словаря. Копия поверхностная, вложенные объекты остаются общими, и правка внутри вложенного элемента видна в обеих структурах. Независимый дубль даёт deepcopy, но он дорог, и чаще дешевле не мутировать данные вовсе.