False == 0 et True == 1 est-il un détail d'implémentation ou est-il garanti par le langage?

245

Est-ce garanti False == 0et True == 1en Python (en supposant qu'ils ne sont pas réaffectés par l'utilisateur)? Par exemple, est-il garanti de quelque manière que le code suivant produira toujours les mêmes résultats, quelle que soit la version de Python (à la fois existante et, probablement, future)?

0 == False  # True
1 == True   # True
['zero', 'one'][False]  # is 'zero'

Toute référence à la documentation officielle serait très appréciée!

Edit : Comme indiqué dans de nombreuses réponses, boolhérite de int. La question peut donc être reformulée comme suit: "La documentation dit-elle officiellement que les programmeurs peuvent s'appuyer sur des booléens héritant d'entiers, avec les valeurs 0et1 ?". Cette question est pertinente pour écrire du code robuste qui n'échouera pas à cause des détails d'implémentation!

Eric O Lebigot
la source
63
@ S.Lott: Il existe de nombreuses raisons de poser la question ci-dessus. Ainsi, il existe des cas où le fait de compter sur des booléens étant des entiers rend votre code plus simple: devez-vous le changer? Ou, vous pouvez repérer des endroits dans un code écrit par quelqu'un d'autre qui s'appuie sur des booléens étant des entiers: interrompez-vous ce que vous modifiez dans le code afin de "corriger" le code existant, ou pouvez-vous être assuré que le codage actuel est sain ? Il existe une pléthore d'autres exemples. Plus généralement, il est bon de connaître les règles du jeu, afin que vous puissiez bien le jouer et le programmer de manière saine.
Eric O Lebigot
10
@ S.Lott: Le message d'origine fait écho précisément à votre argument: la question est essentiellement "Est-ce un détail d'implémentation?", Car je suis entièrement d'accord avec vous sur l'idée qu'il ne faut pas dépendre des détails d'implémentation. Si les booléens sont officiellement des entiers de valeurs connues, le code de la question ne dépend pas des détails d'implémentation, ce qui est bien.
Eric O Lebigot
5
@S. Lot: Sachant que False == 0 et True == 1, il est plus facile de compter le nombre de bools dans une séquence: vous pouvez simplement écrire sum(bool_list). Sinon, il faudrait écrire sum(1 for x bool_list if x).
dan04
8
@dan: C'est une façon de compter les booléens. Je dirais que bool_list.count(True)c'est plus explicite; c'est aussi environ 3 fois plus rapide… :)
Eric O Lebigot
2
@akonsu Comme le montrent les réponses, les booléens Python sont en fait (une sous-classe spécifique de) entiers. De plus, Python a évidemment des types; peut-être que vous vouliez dire qu'il n'est "pas typé statiquement"? De plus, je ne suis pas sûr de ce que vous entendez par "je ne ferais pas d'erreurs dans le code". Maintenant, je n'aime jamais mélanger des booléens avec des entiers, car ils sont conceptuellement différents, et cela ne me dérangerait pas si les booléens Python n'étaient pas des entiers, mais sachant qu'ils le sont, avec les valeurs 0 et 1, est utile.
Eric O Lebigot

Réponses:

184

Dans Python 2.x, cela n'est pas garanti car il est possible Trueet Falseréassigné. Cependant, même si cela se produit, boolean True et boolean False sont toujours correctement renvoyés pour les comparaisons.

En Python 3.x Trueet Falsesont des mots clés et seront toujours égaux à 1et 0.

Dans des circonstances normales en Python 2, et toujours en Python 3:

Falseobjet est de type boolqui est une sous-classe de int:

object
   |
 int
   |
 bool

C'est la seule raison pour laquelle dans votre exemple, ['zero', 'one'][False]cela fonctionne. Cela ne fonctionnerait pas avec un objet qui n'est pas une sous-classe d'entiers, car l'indexation de liste ne fonctionne qu'avec des entiers ou des objets qui définissent une __index__méthode (merci mark-dickinson ).

Éditer:

C'est vrai de la version actuelle de python et de celle de Python 3. Les documents pour python 2.6 et les documents pour Python 3 disent tous les deux:

Il existe deux types d'entiers: [...] Entiers (int) [...] Booléens (bool)

et dans la sous-section booléenne:

Booléens: ceux-ci représentent les valeurs de vérité False et True [...] Les valeurs booléennes se comportent respectivement comme les valeurs 0 et 1, dans presque tous les contextes, à l'exception du fait que lorsqu'elles sont converties en chaîne, les chaînes "False" ou "True "sont retournés, respectivement.

Il y a aussi, pour Python 2 :

Dans des contextes numériques (par exemple, lorsqu'ils sont utilisés comme argument d'un opérateur arithmétique), ils [False et True] se comportent respectivement comme les entiers 0 et 1.

Les booléens sont donc explicitement considérés comme des entiers dans Python 2.6 et 3.

Vous êtes donc en sécurité jusqu'à ce que Python 4 arrive. ;-)

Olivier Verdier
la source
2
0 == 0,0 renvoie Vrai tandis que ['zéro', 'un'] [0,0] échoue. ['zéro', 'un'] [Faux] fonctionne car bool est une sous-classe d'int. (int .__ sous-classes __ () renvoie [<type 'bool'>])
luc
20
Nitpick: tout objet qui fournit une __index__méthode peut être utilisé comme index de liste; pas seulement des sous-classes de intou long.
Mark Dickinson
Ah oui, c'est là aussi. Mais il serait préférable de ne pas créer de lien vers la documentation Python 3.0: 3.0 est mort. :)
Mark Dickinson
4
Re: "En Python 2.x, cela n'est pas garanti car il est possible que True et False soient réaffectés". À mon humble avis, bien que cela soit vrai, quiconque réaffecte Vrai ou Faux mérite toutes les conséquences étranges qu'il obtient. Plus précisément, le stockage de True avant la réaffectation, puis la comparaison du résultat à True après la réaffectation, se rompraient. a = True; True = 'i am an idiot'; a == True=> Faux. Hormis une telle réaffectation, les valeurs par défaut sont normalisées à 0 et 1, et je pense que c'est une pratique courante de dépendre de cela; par exemple pour indexer dans un tableau à deux éléments, où [0] contient le faux cas, [1] vrai.
ToolmakerSteve
Je viens de remarquer une autre confirmation officielle du fait que True peut en pratique être considéré comme 1 et False 0: docs.python.org/2/library/stdtypes.html#boolean-values . J'ajoute ceci à cette réponse.
Eric O Lebigot
78

Lien vers le PEP discutant du nouveau type de booléen dans Python 2.3: http://www.python.org/dev/peps/pep-0285/ .

Lors de la conversion d'un booléen en int, la valeur entière est toujours 0 ou 1, mais lors de la conversion d'un int en booléen, la valeur booléenne est True pour tous les entiers sauf 0.

>>> int(False)
0
>>> int(True)
1
>>> bool(5)
True
>>> bool(-5)
True
>>> bool(0)
False
Erik Cederstrand
la source
22

Dans Python 2.x, ce n'est pas du tout garanti:

>>> False = 5
>>> 0 == False
False

Cela pourrait donc changer. Dans Python 3.x, True, False et None sont des mots réservés , donc le code ci-dessus ne fonctionnerait pas.

En général, avec les booléens, vous devez supposer que si False aura toujours une valeur entière de 0 (tant que vous ne la modifiez pas, comme ci-dessus), True pourrait avoir n'importe quelle autre valeur. Je ne m'appuierais pas nécessairement sur une garantie True==1, mais sur Python 3.x, ce sera toujours le cas, quoi qu'il arrive.

Daniel G
la source
3
Re "True pourrait avoir toute autre valeur. Je ne compterais pas nécessairement sur une garantie que True == 1". En fait, vous POUVEZ compter sur True == 1, selon python.org/dev/peps/pep-0285 , et spec docs.python.org/2/reference/… "Les valeurs booléennes se comportent respectivement comme les valeurs 0 et 1, , dans presque tous les contextes ... "Je ne dis pas qu'il est impossible de remplacer cela dans Py 2 en réaffectant True ou False, mais je dis qu'à moins qu'un programmeur sur votre projet soit un idiot et fasse une telle réaffectation, le le comportement est garanti.
ToolmakerSteve
-2

Très simple. Comme bool concerne l'évaluation d'un entier comme un bool, SEULEMENT zéro donne une fausse réponse. TOUTES les valeurs non nulles, les flottants, les entiers, y compris les nombres négatifs, ou ce que vous avez, renverront vrai.

Un bon exemple de la raison pour laquelle cela est utile est de déterminer l'état d'alimentation d'un périphérique. On est une valeur non nulle, off est zéro. Sur le plan électronique, cela a du sens.

Pour déterminer vrai ou faux relativement entre les valeurs, vous devez avoir quelque chose à comparer. Ceci est valable pour les chaînes et les valeurs numériques, en utilisant ==ou !=ou <, > >=, <=, etc.

Vous pouvez affecter un entier à une variable, puis obtenir la valeur true ou false en fonction de cette valeur de variable.

Kathy
la source
1
La question est de savoir si True == 1 est garanti par Python, pas la valeur booléenne des entiers.
Eric O Lebigot
-3

Il suffit d'écrire int(False)et vous obtiendrez 0, si vous tapez, int(True)il sortira1

Rathee dur
la source
4
Cela signifie seulement que False et True sont des entrées valides pour int(), avec une signification numérique simple, pas qu'elles sont exactement identiques à 0 et 1.
Eric O Lebigot
-5

Faux est un bool. Il a un type différent. C'est un objet différent de 0 qui est un entier.

0 == Falserenvoie True car False est converti en un entier. int (False) renvoie 0

La documentation python de l'opérateur == dit (help ('==')):

Les opérateurs <, >, ==, >=, <=et !=comparer les valeurs de deux objets. Les objets n'ont pas besoin d'avoir le même type. Si les deux sont des nombres, ils sont convertis en un type commun.

En conséquence, False est converti en un entier pour les besoins de la comparaison. Mais c'est différent de 0.

>>> 0 is False
False
luc
la source
26
Ce n'est pas tout à fait vrai: boolest une sous-classe de int, donc dans un sens très réel, un booléen est un entier. Par exemple, isinstance(True, int)renvoie True. Et le contrôle d'égalité ne convertit pas le booléen en entier, car aucune conversion n'est nécessaire: il appelle simplement int.__cmp__directement. Notez bool.__cmp__ is int.__cmp__qu'évalue également True.
Mark Dickinson
3
-1 pour cette réponse. Description incorrecte de la relation entre bool et int (en Python 2). isinstance(True, int)=> Vrai. C'est-à-dire que True EST un entier et ne nécessite pas de conversion.
ToolmakerSteve
J'avais un script qui renvoyait False ou un Int ... en utilisant while response is Falsetravaillé, et while response == Falsenon .. Merci!
curly_brackets
5
C'est 0 is Falsefaux ne vous dit rien. Dans votre interprète interactif, entrez x = -10, puis y = -10, puis x is yet ce sera également faux. Ce n'est pas parce qu'il y a des optimisations en place que l'interpréteur Python réutilise les mêmes objets entiers dans certaines circonstances (stockage de littéraux entiers sous forme de constantes, internement de petits entiers) que cela ne isdevrait pas être utilisé lorsque vous souhaitez tester l' égalité des valeurs entières .
Martijn Pieters