37 votes

Comment se fait-il que je puisse ajouter la valeur booléenne False mais pas True dans un ensemble en Python ?

Je viens de commencer à étudier le type de données set en Python. Pour une raison quelconque, lorsque j'ajoute la valeur booléenne True à un ensemble, elle n'apparaît pas. Cependant, si j'ajoute False à un ensemble, il devient un élément de l'ensemble. J'ai été choqué lorsque j'ai cherché cette question sur Google et que rien n'a été trouvé.

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

print(example1)
print(example2)

La sortie est :

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

1 votes

Si true est égal à 1 et false est 0, true est déjà dans l'ensemble et ne sera donc pas ajouté à nouveau.

2 votes

print({0, False})

0 votes

Mon Python 3.5.1 dit {True, 2, 4, 7} et le 1 est parti. Python est parfois impythique

41voto

Andrej Kesely Points 20452

Parce qu'en Python 1 == True (et hash(1) == hash(True) ) et vous en avez déjà un dans votre jeu.

Imaginez cet exemple :

example1 = {0, False, None}
example2 = {1, True}

print(example1)
print(example2)

La sortie est prévue :

{0, None}
{1}

Le premier jeu a 0 y None parce que 0 == False mais 0 != None . Avec la deuxième série 1 == True donc True n'est pas ajouté à l'ensemble.

1 votes

J'ajouterai que si vous changez l'ordre (c'est-à-dire si vous placez les booléens avant les int dans la définition du littéral de l'ensemble), le résultat sera {False, None} et {True}.

16voto

user3483203 Points 28606

La raison pour laquelle vous perdez les valeurs booléennes d'une set s'ils contiennent déjà 0 o 1 c'est parce que le comportement suivant...

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

... est garanti dans Python 3.x .

Ce qui signifie que vous ne pouvez pas avoir les deux dans un ensemble :

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

Les hachages étant égaux, c'est tout aussi important que les objets sont égaux, car des objets qui sont "égaux" peuvent produire des hachages différents et vice versa :

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>}

Vous pouvez également avoir un set qui contient des éléments avec les mêmes hachages, si ces éléments ne sont pas égaux :

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

Ce comportement est no garanti dans Python 2.x, pour la simple raison que True y False ne sont pas des mots-clés réservés (ce changement a été introduit dans la version 3.x ). Vous pouvez les réaffecter (bien qu'il soit préférable de ne pas le faire), il n'y a donc aucune raison pour que le même comportement s'applique à Python 2.x :

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

Mais ne laissez pas le fait que True a été remplacé par 5 vous décourager ! On peut abuser de la représentation d'une classe pour faire croire que True est vraiment dans le jeu :

class Foo(object):
    def __repr__(self):
        return('True')

>>> True = Foo()
>>> set([1, True])
set([1, True])

Il est évident que les deux derniers extraits de code sont de mauvaises pratiques et ne servent qu'à des fins de démonstration. L'essentiel est que des objets égaux ayant le même hash ne peuvent être contenus dans le même fichier set et dans Python 3.x, 1 y True y 0 y False auront toujours le même hash, et seront toujours égaux.

0 votes

"des objets qui sont "égaux" peuvent produire des hachages différents et vice versa" - s'ils font cela, ils sont cassés. Par exemple, votre Foo y Bar sont cassées parce que leurs __eq__ ne renvoie pas NotImplemented pour les types non reconnus.

1voto

bit chaser Points 186

Faux et Vrai sont égaux à 0 et 1, respectivement. Ce sont des entités distinctes, et pourtant ces deux valeurs égales ne peuvent pas figurer toutes les deux dans un ensemble. Il s'agit clairement d'un comportement indésirable, mais il n'est pas certain qu'il puisse être corrigé tout en permettant à la multiplication par une valeur booléenne de fonctionner comme prévu.

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}

Remarquez que selon l'ordre dans lequel on les place dans l'ensemble, 1 ne sera pas dans l'ensemble si Vrai y est déjà, et Vrai ne sera pas dans l'ensemble si 1 y est déjà.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X