Los conjuntos y los dictos están optimizados para diferentes casos de uso. El uso principal de un conjunto es la prueba rápida de membresía, que es independiente del orden. Para los dictados, el costo de la búsqueda es la operación más crítica, y es más probable que la clave esté presente. Con los conjuntos, la presencia o ausencia de un elemento no se conoce de antemano, por lo que la implementación del conjunto debe optimizarse tanto para el caso encontrado como para el no encontrado. Además, algunas optimizaciones para las operaciones de conjuntos comunes, como la unión y la intersección, dificultan la retención del orden de conjuntos sin degradar el rendimiento.
Si bien ambas estructuras de datos están basadas en hash, es un error común pensar que los conjuntos solo se implementan como dictados con valores nulos. Incluso antes de la implementación compacta dict en CPython 3.6, las implementaciones set y dict ya diferían significativamente, con poca reutilización de código. Por ejemplo, los dictos usan sondeo aleatorio, pero los conjuntos usan una combinación de sondeo lineal y direccionamiento abierto, para mejorar la localidad de caché. La sonda lineal inicial ( 9 pasos predeterminados en CPython) verificará una serie de pares clave / hash adyacentes, mejorando el rendimiento al reducir el costo del manejo de colisiones hash: el acceso consecutivo a la memoria es más barato que las sondas dispersas.
En teoría, sería posible cambiar la implementación establecida de CPython para que sea similar al dict compacto, pero en la práctica hay inconvenientes, y los desarrolladores principales notables se opusieron a hacer tal cambio.
Los conjuntos permanecen sin ordenar. (¿Por qué? Los patrones de uso son diferentes. Además, la implementación es diferente).
- Guido van Rossum
Los conjuntos utilizan un algoritmo diferente que no es tan fácil de retener el orden de inserción. Las operaciones de conjunto a conjunto pierden su flexibilidad y optimizaciones si se requiere orden. Las matemáticas de conjuntos se definen en términos de conjuntos no ordenados. En resumen, el orden establecido no está en el futuro inmediato.
- Raymond Hettinger
Puede encontrar una discusión detallada sobre si se compactarán conjuntos para 3.7, y respuestas sobre por qué se decidió en contra, en las listas de correo python-dev.
En resumen, los puntos principales son que los patrones de uso son diferentes (los dictados de orden de inserción como ** kwargs son útiles , menos para los conjuntos), el ahorro de espacio para los conjuntos de compactación es menos significativo (porque solo hay claves y matrices hash para densificar, en lugar de claves, valores hash y valores), y la optimización de sondeo lineal antes mencionada en conjuntos es incompatible con una implementación compacta.
Reproduciré la publicación de Raymond a continuación que cubre los puntos más importantes.
El 14 de septiembre de 2016, a las 3:50 PM, Eric Snow escribió:
Entonces, haré lo mismo con los sets.
A menos que haya entendido mal, Raymond se opuso a hacer un cambio similar para establecer.
Así es. Aquí hay algunos pensamientos sobre el tema antes de que la gente comience a correr salvajemente.
Para el dict compacto, el ahorro de espacio fue una ganancia neta con el espacio adicional consumido por los índices y la sobreasignación para las matrices de clave / valor / hash que se compensó con creces por la densidad mejorada de las matrices de clave / valor / hash. Sin embargo, para los conjuntos, la red fue mucho menos favorable porque todavía necesitamos los índices y la sobreasignación, pero solo puede compensar el costo de espacio al densificar solo dos de los tres conjuntos. En otras palabras, la compactación tiene más sentido cuando se desperdicia espacio para claves, valores y valores hash. Si pierde uno de esos tres, deja de ser convincente.
El patrón de uso para conjuntos es diferente de los dictados. El primero tiene más búsquedas al azar. Este último tiende a tener menos búsquedas de claves faltantes. Además, algunas de las optimizaciones para las operaciones de conjunto a conjunto dificultan la retención del orden de conjuntos sin afectar el rendimiento.
Seguí un camino alternativo para mejorar el rendimiento del set. En lugar de compactar (que no era mucho espacio para ganar e incurría en el costo de una indirección adicional), agregué un sondeo lineal para reducir el costo de las colisiones y mejorar el rendimiento de la caché. Esta mejora es incompatible con el enfoque de compactación que recomendé para los diccionarios.
Por ahora, el efecto secundario de ordenar en los diccionarios no está garantizado, por lo que es prematuro comenzar a insistir en que los conjuntos también se ordenen. Los documentos ya enlazan con una receta para crear un OrderedSet (
https://code.activestate.com/recipes/576694/ ) pero parece que la aceptación ha sido casi nula. Además, ahora que Eric Snow nos ha dado un OrderedDict rápido, es más fácil que nunca construir un OrderedSet a partir de MutableSet y OrderedDict, pero nuevamente no he observado ningún interés real porque los análisis de datos típicos de set-to-set realmente no Necesita o se preocupa por ordenar. Del mismo modo, el uso principal de las pruebas rápidas de membresía es independiente del orden.
Dicho esto, creo que hay espacio para agregar implementaciones de conjuntos alternativos a PyPI. En particular, hay algunos casos especiales interesantes para los datos que se pueden ordenar en los que las operaciones de conjunto a conjunto se pueden acelerar comparando rangos completos de claves (consulte
https://code.activestate.com/recipes/230113-implementation-of- establece-usando-listas-ordenadas
para un punto de partida). IIRC, PyPI ya tiene código para filtros de floración y hash cuckoo.
Comprendo que es emocionante tener un gran bloque de código aceptado en el núcleo de Python, pero eso no debería abrirse a las compuertas para participar en reescrituras más importantes de otros tipos de datos a menos que estemos seguros de que está garantizado.
- Raymond Hettinger
De [Python-Dev] Python 3.6 dict se vuelve compacto y obtiene una versión privada; y las palabras clave se ordenan , septiembre de 2016.