¿Por qué puedo agregar el valor booleano Falso pero no Verdadero en un conjunto en Python?

Acabo de comenzar a investigar el tipo de datos establecido en Python. Por alguna razón, cada vez que agrego el valor booleano de True a un conjunto no aparece. Sin embargo, si agrego False a un conjunto, se convertirá en un elemento del conjunto. Me sorprendió cuando busqué en Google esta pregunta que no surgió nada.

example1 = {1, 2, 7, False} example2 = {7, 2, 4, 1, True} print(example1) print(example2) 

La salida es:

 {False, 1, 2, 7} {1, 2, 4, 7} 

Porque en Python 1 == True (y hash(1) == hash(True) ) y ya tienes 1 en tu set.

Imagina este ejemplo:

 example1 = {0, False, None} example2 = {1, True} print(example1) print(example2) 

Saldrá:

 {0, None} {1} 

El primer conjunto tiene 0 y None porque 0 == False pero 0 != None . Con el segundo conjunto 1 == True entonces True no se agrega al conjunto.

La razón por la que está perdiendo valores booleanos de un set si ya contienen 0 o 1 es porque el siguiente comportamiento …

 >>> hash(1) == hash(True) True >>> hash(0) == hash(False) True >>> 1 == True >>> True >>> 0 == False >>> True 

… está garantizado en Python 3.x.

Lo que significa que no puedes tener ambos en un set:

 >>> set([True, 1]) {True} >>> set([False, 0]) {False} 

La igualdad de hashes es tan importante como la igualdad de los objetos, porque los objetos que son “iguales” pueden producir hashes diferentes y viceversa:

 class Foo: def __init__(self, x): self.x = x def __hash__(self): return 1 def __eq__(self, other): return self.x == other.x class Bar: def __init__(self, x): self.x = x def __hash__(self): return 2 def __eq__(self, other): return self.x == other.x >>> x = Foo(3) >>> y = Bar(3) >>> x == y True >>> hash(x) == hash(y) False >>> set([x, y]) {<__main__.Bar at 0x56ed278>, <__main__.Foo at 0x5707390>} 

También puede tener un set que contenga elementos con los mismos hashes, si esos elementos no son iguales:

 >>> hash('a') -904409032991049157 >>> hash(-904409032991049157) -904409032991049157 >>> hash('a') == hash(-904409032991049157) True >>> set(['a', -904409032991049157]) {-904409032991049157, 'a'} 

Este comportamiento no está garantizado en Python 2.x, por la sencilla razón de que True y False no son palabras clave reservadas (este cambio se introdujo en 3.x ). Puedes reasignarlos (aunque es mejor que no), por lo que no hay razón para que el mismo comportamiento se cumpla en Python 2.x:

 >>> True = 5 >>> hash(True) == hash(1) False >>> set([1, True]) set([1, 5]) 

¡Pero no dejes que el hecho de que True sido reemplazado por 5 te desanime! Podemos abusar de la representación de una clase para que parezca que True realmente está en el conjunto:

 class Foo(object): def __repr__(self): return('True') >>> True = Foo() >>> set([1, True]) set([1, True]) 

Obviamente, los últimos fragmentos de código de pareja son una mala práctica, y son solo para demostración. La idea principal es que los objetos iguales con el mismo hash no pueden estar contenidos en el mismo set , y en Python 3.x, 1 y True , y 0 y False , siempre tendrán el mismo hash y siempre serán iguales.

Falso y Verdadero son iguales a 0 y 1, respectivamente. Son entidades distintas, pero los dos valores iguales no pueden estar en un conjunto. Esto es claramente un comportamiento no deseado, pero no está claro si se puede arreglar y aún así permitir que la multiplicación por un valor booleano funcione como está documentado.

 IPython 6.2.1 -- An enhanced Interactive Python. 1 is True Out[1]: False {1,True} Out[2]: {1} {0,False} Out[3]: {0} {False, 0} Out[4]: {False} {True, 1} Out[5]: {True} 

Tenga en cuenta que, según el orden en que se colocaron en el conjunto, 1 no estará en el conjunto si la Verdadera ya está en él, y la Verdad no estará en el conjunto si 1 ya está en ella.