python - sacar - ¿Por qué son iguales las tuplas construidas a partir de conjuntos inicializados de manera diferente?
sacar elementos de una lista python (4)
A primera vista, parece que x
siempre debe ser igual a y
, porque dos conjuntos construidos a partir de los mismos elementos son siempre iguales:
>>> x = set([1, "a", "b", "c", "z", "f"])
>>> y = set(["a", "b", "c", "z", "f", 1])
>>> x
{1, ''z'', ''a'', ''b'', ''c'', ''f''}
>>> y
{1, ''z'', ''a'', ''b'', ''c'', ''f''}
>>> x == y
True
Sin embargo , no siempre es el caso de que las tuplas (u otras colecciones ordenadas) construidas a partir de dos conjuntos iguales sean iguales.
De hecho, el resultado de su comparación a veces es True
y, a veces False
, al menos en Python> = 3.3. Probando el siguiente código:
# compare.py
x = tuple(set([1, "a", "b", "c", "z", "f"]))
y = tuple(set(["a", "b", "c", "z", "f", 1]))
print(x == y)
... mil veces:
$ for x in {1..1000}
> do
> python3.3 compare.py
> done | sort | uniq -c
147 False
853 True
Esto se debe a que, desde Python 3.3, los valores hash de cadenas, bytes y fechas y horas se aleatorizan como resultado de una corrección de seguridad . Dependiendo de lo que sean los hash, pueden producirse "colisiones", lo que significará que los elementos de pedido se almacenan en el conjunto subyacente (y, por lo tanto, el orden de iteración) depende del orden de inserción.
Aquí está el bit relevante de los documentos:
Mejoras de seguridad:
- La aleatorización Hash está activada por defecto.
EDITAR : Dado que en los comentarios se menciona que la relación True
/ False
anterior es superficialmente sorprendente ...
Los conjuntos, como los diccionarios, se implementan como tablas hash, por lo que si hay una colisión, el orden de los elementos en la tabla (y el orden de iteración) dependerá de qué elemento se agregó primero (diferente en x
y y
en este caso ) y la semilla utilizada para hashing (diferente en todas las invocaciones de Python desde 3.3). Dado que las colisiones son raras por diseño, y los ejemplos en esta pregunta son conjuntos pequeños, el problema no surge tan a menudo como uno podría suponer inicialmente.
Para una explicación detallada de la implementación de diccionarios y conjuntos de Python, vea The Mighty Dictionary .
Esperaba las siguientes dos tuplas
>>> x = tuple(set([1, "a", "b", "c", "z", "f"]))
>>> y = tuple(set(["a", "b", "c", "z", "f", 1]))
para comparar desigual, pero no:
>>> x == y
>>> True
¿Porqué es eso?
Hay dos cosas en juego aquí.
Los conjuntos están desordenados.
set([1, "a", "b", "c", "z", "f"])) == set(["a", "b", "c", "z", "f", 1])
Cuando convierte un conjunto en una tupla a través del constructor de
tuple
, esencialmente itera sobre el conjunto y agrega cada elemento devuelto por la iteración.
La sintaxis del constructor para tuplas es
tuple(iterable) -> tuple initialized from iterable''s items
Llamar a tuple(set([1, "a", "b", "c", "z", "f"]))
es lo mismo que llamar a tuple([i for i in set([1, "a", "b", "c", "z", "f"])])
Los valores para
[i for i in set([1, "a", "b", "c", "z", "f"])]
y
[i for i in set(["a", "b", "c", "z", "f", 1])]
son lo mismo que itera sobre el mismo conjunto.
EDITAR gracias a @ZeroPiraeus (compruebe su answer ). Esto no está garantizado El valor de la iteración no siempre será el mismo incluso para el mismo conjunto.
El constructor de tuplas no sabe el orden en que se construye el conjunto.
Los conjuntos no están ordenados y solo están definidos por su membresía.
Por ejemplo, set([1, 2]) == set([2, 1])
Las tuplas son iguales si sus miembros en cada posición son iguales, pero dado que las colecciones de las tuplas se crearon para que se repitan por igual (en orden creciente), las tuplas también terminan siendo iguales.
por lo que tiene dos listas, que tienen el mismo contenido pero en diferentes órdenes, las convierte en conjuntos, que serán iguales, ya que tienen el mismo contenido.
Cuando convierte esos conjuntos en tuplas, se convertirán en el mismo orden, ya que son el mismo conjunto, por lo que las tuplas serán las mismas.
Esto es cierto en Python2.7, pero desde 3.3 en adelante cuando los hashes son aleatorizados no podrás garantizar esto, ya que los dos conjuntos, aunque sean iguales en contenido, no necesariamente iterarán en el mismo orden.