Наборы и дикты оптимизированы для разных вариантов использования. Основное использование набора - быстрое тестирование членства, которое не зависит от порядка. Для диктов стоимость поиска является наиболее важной операцией, и ключ, скорее всего, будет присутствовать. При использовании наборов наличие или отсутствие элемента заранее неизвестно, и поэтому реализация набора должна оптимизироваться как для найденного, так и для не найденного случая. Кроме того, некоторые оптимизации для общих операций над множествами, таких как объединение и пересечение, затрудняют сохранение порядка множеств без снижения производительности.
Хотя обе структуры данных основаны на хэше, распространенное заблуждение состоит в том, что наборы просто реализуются как диктовки с нулевыми значениями. Еще до реализации компактного dict в CPython 3.6 реализации set и dict уже значительно отличались, с небольшим повторным использованием кода. Например, в диктовках используется рандомизированное зондирование, но в наборах используется комбинация линейного зондирования и открытой адресации для улучшения локальности кэша. Первоначальный линейный зонд ( 9 шагов по умолчанию в CPython) проверит ряд смежных пар ключ / хэш, улучшая производительность за счет снижения затрат на обработку коллизий хэшей - последовательный доступ к памяти дешевле, чем разбросанных проб.
Теоретически было бы возможно изменить реализацию набора CPython, чтобы она была похожа на компактный, но на практике есть недостатки, и известные разработчики ядра были против такого изменения.
Наборы остаются неупорядоченными. (Почему? Шаблоны использования разные. Кроме того, разные реализации.)
- Гвидо ван Россум
Наборы используют другой алгоритм, который не так легко изменить, чтобы сохранить порядок вставки. Операции с установкой на установку теряют свою гибкость и оптимизацию, если требуется порядок. Математика множеств определяется в терминах неупорядоченных множеств. Короче говоря, порядок упорядочения не в ближайшем будущем.
- Раймонд Хеттингер
Подробное обсуждение вопроса о том, следует ли компактизировать наборы для 3.7, и ответы о том, почему было принято решение, можно найти в списках рассылки python-dev.
Таким образом, основные моменты заключаются в том, что шаблоны использования различны ( полезны правила размещения вставок, такие как ** kwargs , в меньшей степени - для наборов), экономия пространства для компактных наборов менее значительна (поскольку для уплотнения, в отличие от ключей, хэшей и значений), и вышеупомянутая линейная зондирование в наборах несовместима с компактной реализацией.
Я воспроизведу пост Рэймонда ниже, который охватывает наиболее важные моменты.
14 сентября 2016 года в 15:50 Эрик Сноу написал:
Затем я сделаю то же самое с сетами.
Если я не понял неправильно, Рэймонд был против внесения аналогичных изменений в настройках.
Вот так. Вот несколько мыслей на эту тему, прежде чем люди начнут нервничать.
Для компактного режима экономия пространства была чистой победой благодаря дополнительному пространству, занимаемому индексами, а перераспределение для массивов ключ / значение / хэш было более чем компенсировано улучшенной плотностью массивов ключ / значение / хэш. Однако для сетов сеть была гораздо менее благоприятной, потому что нам все еще нужны индексы и перераспределение, но мы можем только компенсировать стоимость пространства, уплотняя только два из трех массивов. Другими словами, сжатие имеет больше смысла, когда вы теряете место для ключей, значений и хэшей. Если вы потеряете один из этих трех, он перестает быть убедительным.
Шаблон использования для наборов отличается от диктов. У первого больше или меньше попаданий. У последнего, как правило, меньше пропущенных ключевых слов. Кроме того, некоторые из оптимизаций для операций набора к установке затрудняют сохранение порядка набора без влияния на производительность.
Я искал альтернативный путь для улучшения производительности набора. Вместо сжатия (что не было значительным выигрышем в космосе и привело к дополнительным издержкам), я добавил линейное зондирование, чтобы снизить стоимость коллизий и повысить производительность кэша. Это улучшение несовместимо с подходом к сжатию, который я отстаивал для словарей.
Пока побочный эффект упорядочения в словарях не гарантирован, поэтому преждевременно начинать настаивать на том, что множества также упорядочиваются. Документы уже ссылаются на рецепт для создания OrderedSet (
https://code.activestate.com/recipes/576694/ ), но похоже, что использование было почти нулевым. Кроме того, теперь, когда Эрик Сноу дал нам быстрый OrderedDict, проще, чем когда-либо, создать OrderedSet из MutableSet и OrderedDict, но, опять же, я не заметил особого интереса, потому что типичная аналитика данных типа «набор-набор» на самом деле не нужно или заботиться о заказе. Аналогично, основное использование быстрых проверок членства - независимость от порядка.
Тем не менее, я думаю, что есть место для добавления альтернативных реализаций множеств в PyPI. В частности, существуют некоторые интересные особые случаи для данных, которые можно заказать, когда операции set-to-set могут быть ускорены путем сравнения целых диапазонов ключей (см.
Https://code.activestate.com/recipes/230113-implementation-of- устанавливает-используя-отсортированные списки
для начальной точки). Во IIRC, PyPI уже есть код для фильтров типа Блума и хеширования кукушки.
Я понимаю, что это захватывающе, когда основной блок кода принимается в ядро Python, но это не должно открывать возможности для более серьезных переписываний других типов данных, если мы не уверены, что это оправдано.
- Раймонд Хеттингер
С [Python-Dev] Python 3.6 dict становится компактным и получает приватную версию; и ключевые слова становятся упорядоченными , сентябрь 2016.