Как изменяется свойство изменяемости при вложении изменяемого списка в неизменяемый объект в Python
Что проверяют
Понимаете ли вы разницу между неизменяемостью контейнера и неизменяемостью его содержимого. Следом почти всегда спрашивают, можно ли такой кортеж сделать ключом словаря и что произойдёт после t[0] += [4].
Как отвечать
Кортеж хранит не сами объекты, а ссылки на них. Неизменяемость означает, что нельзя заменить ссылку, удалить или добавить элемент. Объект, на который указывает ссылка, живёт своей жизнью:
t = ([1, 2], 3), затемt[0].append(4): сработает, кортеж теперь([1, 2, 4], 3);t[0] = [9]:TypeError, подменить ссылку нельзя;- хэшируемость:
hash(t)падает сTypeError: unhashable type: 'list', поэтому такой кортеж не станет ключомdict, элементомsetи не пройдёт аргументом в функцию подfunctools.lru_cache; t[0] += [4]: классическая ловушка. Список расширяется на месте через__iadd__, а затем присваивание в кортеж падает сTypeError. Ошибка есть, но список уже изменён;- копирование:
copy.copy(t)вернёт тот же кортеж, аcopy.deepcopy(t)создаст новый вместе с новыми списками внутри.
Свяжите это с работой в данных. Конфиги экспериментов в кортежах, ключи кэша для признаков, параметры по умолчанию вида def f(cols=[]): всё это места, где изменяемый объект внутри «неизменяемой» обёртки приводит к тихой порче, которую потом ищут днями.
Если нужна настоящая неизменяемость, вкладывайте неизменяемое: кортеж вместо списка, frozenset вместо set, types.MappingProxyType для словаря только на чтение, у массива NumPy флаг arr.flags.writeable = False. @dataclass(frozen=True) ведёт себя как кортеж: запрещает переприсвоить поле, но список в поле остаётся изменяемым.
Где спотыкаются
Отвечают «кортеж неизменяемый, значит и список внутри не изменить». Это неверно, и интервьюер тут же покажет append.
Не знают поведения t[0] += [4] и уверенно говорят, что список остался прежним, раз вылетела ошибка.
Путают неизменяемость с хэшируемостью и считают, что любой кортеж можно положить в set. Хэшируется только кортеж, все элементы которого хэшируемы.