В set comprehension два разных объекта имеют одинаковый хэш и сравниваются как равные. Сколько элементов окажется в результате?
В результате окажется один элемент. Множество хранит только один экземпляр каждого набора объектов, которые имеют одинаковый хэш и равны между собой.
Множества предназначены для хранения уникальных элементов и быстрого membership-тестирования — проверки, входит ли значение в коллекцию. Set comprehension предоставляет компактный способ построить такое множество, одновременно вычисляя элементы и автоматически устраняя дубликаты.
При преобразовании данных в множество количество исходных элементов может уменьшиться. Это опасно, если разработчик ожидает сохранения всех записей или различий между объектами, которые логически считаются равными.
Кроме того, корректность работы множества зависит от согласованности методов hash и eq. Если равные объекты имеют разные хэши, поиск и удаление элементов могут вести себя непредсказуемо с точки зрения логики приложения.
При добавлении результата в множество Python сначала использует хэш, чтобы найти подходящую область поиска, а затем проверяет равенство с уже существующими элементами. Если найден равный элемент, новый элемент не добавляется.
Например:
Результат — 1: два разных объекта признаны равными и имеют одинаковый хэш. Множество не сохраняет дубликаты, но не следует полагаться на порядок элементов или на то, какой из равных экземпляров будет наблюдаемым.
Контракт важен: если a == b, то должно выполняться hash(a) == hash(b). Обратное не требуется: одинаковый хэш ещё не означает равенство, потому что коллизии хэшей допустимы и разрешаются проверкой eq.
Также нежелательно изменять поля объекта, участвующие в хэше, после добавления объекта в множество. Тогда объект может оказаться в позиции, соответствующей старому хэшу, и перестать корректно находиться через проверку членства.
Сервис собирает уникальные идентификаторы пользователей из нескольких источников. Вариант со списком сохраняет повторы и требует отдельной проверки перед каждым добавлением. Вариант с множеством автоматически убирает повторы и обычно обеспечивает быстрые проверки наличия, но не сохраняет порядок как основное свойство структуры.
Если порядок не важен, выбирают множество или set comprehension. Если нужно сохранить порядок первого появления, применяют словарь с уникальными ключами или отдельную структуру дедупликации; это расходует дополнительную память, зато делает порядок частью ожидаемого результата.
В результате выбор зависит от требования: уникальность и быстрый поиск — множество, уникальность вместе с порядком — другая структура данных.
Нет. Одинаковый хэш только направляет поиск в одну область. Затем Python проверяет равенство объектов. Поэтому коллизия хэшей сама по себе не приводит к удалению разных элементов.
Множество сначала использует хэш как быстрый фильтр. Если равные объекты имели бы разные хэши, они попали бы в разные области и множество могло бы сохранить оба объекта, нарушив ожидаемую семантику равенства. Несколько неравных объектов могут иметь один хэш, поэтому после совпадения хэша выполняется дополнительная проверка равенства.
Если изменено поле, влияющее на хэш или равенство, объект может стать практически недоступным через обычную проверку членства. Множество не перестраивает своё внутреннее размещение автоматически. Поэтому элементы множества должны быть хэшируемыми и логически неизменяемыми на протяжении всего времени хранения в множестве; для изменяемых данных обычно используют неизменяемое представление, например кортеж или строку.