¿Es Falso == 0 y Verdadero == 1 un detalle de implementación o está garantizado por el idioma?

244

¿Está garantizado eso False == 0y True == 1, en Python (suponiendo que no sean reasignados por el usuario)? Por ejemplo, ¿se garantiza de alguna manera que el siguiente código siempre producirá los mismos resultados, cualquiera que sea la versión de Python (tanto existentes como futuros)?

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

¡Cualquier referencia a la documentación oficial sería muy apreciada!

Editar : como se señala en muchas respuestas, boolhereda de int. Por lo tanto, la pregunta puede reformularse como: "¿La documentación dice oficialmente que los programadores pueden confiar en los booleanos que heredan de enteros, con los valores 0y1 ?". ¡Esta pregunta es relevante para escribir código robusto que no fallará debido a los detalles de implementación!

Eric O Lebigot
fuente
63
@ S.Lott: Hay muchas razones para hacer la pregunta anterior. Por lo tanto, hay casos en los que confiar en que los booleanos sean enteros simplifica su código: ¿tiene que cambiarlo? O bien, puede detectar lugares en un código escrito por otra persona que confía en que los booleanos son enteros: ¿interrumpe lo que está modificando en el código para "arreglar" el código existente, o puede estar seguro de que la codificación actual es correcta? ? Hay una gran cantidad de otros ejemplos. En términos más generales, es bueno conocer las reglas del juego, para que pueda jugarlo bien y programarlo de una manera sólida.
Eric O Lebigot 05 de
10
@ S.Lott: La publicación original hace eco precisamente de su punto: la pregunta es esencialmente "¿Es esto un detalle de implementación?", Porque estoy totalmente de acuerdo con usted en la idea de que uno no debe depender de los detalles de implementación. Si los booleanos son oficialmente enteros de valores conocidos, entonces el código en la pregunta no depende de los detalles de implementación, lo cual es bueno.
Eric O Lebigot 05 de
55
@S. Lote: Saber que Falso == 0 y Verdadero == 1 hace que sea más fácil contar cuántos bools en una secuencia son verdaderos: solo puede escribir sum(bool_list). De lo contrario, tendrías que escribir sum(1 for x bool_list if x).
dan04
8
@dan: Esa es una forma de contar booleanos. Yo diría que bool_list.count(True)es más explícito; también es aproximadamente 3 veces más rápido ... :)
Eric O Lebigot 05 de
2
@akonsu Como muestran las respuestas, los booleanos de Python son en realidad (una subclase específica de) enteros. Además, Python obviamente tiene tipos; tal vez quisiste decir que "no está estáticamente escrito"? Además, no estoy seguro de lo que quiere decir con "No cometería errores en el código". Ahora, nunca me gusta mezclar booleanos con enteros, porque son conceptualmente diferentes, y no me importaría si los booleanos de Python no fueran enteros, pero saber que son, con valores 0 y 1, es útil.
Eric O Lebigot

Respuestas:

183

En Python 2.x esto no está garantizado, ya que es posible Truey se Falsepuede reasignar. Sin embargo, incluso si esto sucede, boolean True y boolean False aún se devuelven correctamente para las comparaciones.

En Python 3.x Truey Falseson palabras clave y siempre será igual a 1e 0.

En circunstancias normales en Python 2, y siempre en Python 3:

Falseobjeto es de tipo boolque es una subclase de int:

object
   |
 int
   |
 bool

Es la única razón por la cual, en su ejemplo, ['zero', 'one'][False]funciona. No funcionaría con un objeto que no sea una subclase de entero, porque la indexación de listas solo funciona con enteros u objetos que definen un __index__método (gracias mark-dickinson ).

Editar:

Es cierto de la versión actual de Python, y de la de Python 3. Los documentos para Python 2.6 y los documentos para Python 3 dicen:

Hay dos tipos de enteros: [...] enteros (int) [...] booleanos (bool)

y en la subsección booleana:

Booleanos: Estos representan los valores de verdad Falso y Verdadero Los valores [...] booleanos se comportan como los valores 0 y 1, respectivamente, en casi todos los contextos, con la excepción de que cuando se convierten en una cadena, las cadenas "Falso" o "Verdadero" "se devuelven, respectivamente.

También hay, para Python 2 :

En contextos numéricos (por ejemplo, cuando se usa como argumento para un operador aritmético), [Falso y Verdadero] se comportan como los enteros 0 y 1, respectivamente.

Por lo tanto, los booleanos se consideran explícitamente como enteros en Python 2.6 y 3.

Así que estás a salvo hasta que aparezca Python 4. ;-)

Olivier Verdier
fuente
2
0 == 0.0 devuelve Verdadero mientras que ['cero', 'uno'] [0.0] falla. ['cero', 'uno'] [Falso] funciona porque bool es una subclase de int. (int .__ subclasses __ () devuelve [<type 'bool'>])
luc
20
Nitpick: cualquier objeto que proporcione un __index__método puede usarse como un índice de lista; no solo subclases de into long.
Mark Dickinson
Ah sí, también está ahí. Pero sería mejor no vincular a la documentación de Python 3.0: 3.0 está muerto. :)
Mark Dickinson
44
Re: "En Python 2.x esto no está garantizado ya que es posible reasignar True y False". En mi humilde opinión, si bien esto es cierto, cualquiera que reasigne Verdadero o Falso merece cualquier consecuencia extraña que obtenga. Específicamente, almacenar True antes de la reasignación y luego comparar el resultado con True después de la reasignación se rompería. a = True; True = 'i am an idiot'; a == True=> Falso. Aparte de dicha reasignación, los valores predeterminados están estandarizados como 0 y 1, y creo que es una práctica común depender de eso; por ejemplo, para indexar en una matriz de dos elementos, donde [0] contiene el caso falso, [1] verdadero.
ToolmakerSteve
Acabo de notar otra confirmación oficial del hecho de que True en la práctica puede considerarse como 1 y Falso 0: docs.python.org/2/library/stdtypes.html#boolean-values . Estoy agregando esto a esta respuesta.
Eric O Lebigot
78

Enlace al PEP sobre el nuevo tipo de bool en Python 2.3: http://www.python.org/dev/peps/pep-0285/ .

Al convertir un bool en un int, el valor entero siempre es 0 o 1, pero al convertir un int en un bool, el valor booleano es True para todos los enteros excepto 0.

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

En Python 2.x, no está garantizado en absoluto:

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

Entonces podría cambiar. En Python 3.x, Verdadero, Falso y Ninguno son palabras reservadas , por lo que el código anterior no funcionaría.

En general, con booleanos debe suponer que mientras False siempre tendrá un valor entero de 0 (siempre y cuando no lo cambie, como se indicó anteriormente), True podría tener cualquier otro valor. No necesariamente confiaría en ninguna garantía de eso True==1, pero en Python 3.x, este siempre será el caso, pase lo que pase.

Daniel G
fuente
3
Re "True podría tener cualquier otro valor. No necesariamente confiaría en ninguna garantía de que True == 1". En realidad, PUEDE confiar en True == 1, según python.org/dev/peps/pep-0285 , y la especificación docs.python.org/2/reference/… "Los valores booleanos se comportan como los valores 0 y 1, respectivamente , en casi todos los contextos ... "No digo que sea imposible anular esto en Py 2 al reasignar Verdadero o Falso, pero sí digo que a menos que algún programador en su proyecto sea un idiota y haga tal reasignación, el El comportamiento está garantizado.
ToolmakerSteve
-2

Muy simple. Como bool se relaciona con la evaluación de un entero como bool, SOLO cero da una respuesta falsa. TODOS los valores distintos de cero, flotantes, enteros, incluidos los números negativos, o lo que tenga, devolverán verdadero.

Un buen ejemplo de por qué esto es útil es determinar el estado de alimentación de un dispositivo. Encendido es cualquier valor distinto de cero, apagado es cero. Hablando electrónicamente esto tiene sentido.

Para determinar verdadero o falso relativamente entre valores, debe tener algo con lo que compararlo. Esto se aplica a cadenas y valores numéricos, utilizando ==o !=o <, > >=,<= , etc.

Puede asignar un número entero a una variable y luego obtener verdadero o falso según el valor de esa variable.

Kathy
fuente
1
La pregunta es sobre si Verdadero == 1 está garantizado por Python, no sobre el valor booleano de los enteros.
Eric O Lebigot
-3

Simplemente escriba int(False)y obtendrá 0, si escribe int(True), generará1

Rathee duro
fuente
44
Esto solo significa que Falso y Verdadero son entradas válidas para int(), con un significado numérico simple, no que son exactamente idénticos a 0 y 1.
Eric O Lebigot
-5

Falso es un bool. Tiene un tipo diferente. Es un objeto diferente de 0 que es un entero.

0 == Falsedevuelve True porque False se convierte en un entero. int (Falso) devuelve 0

La documentación de Python del operador == dice (ayuda ('==')):

Los operadores <, >, ==, >=, <=, y !=se comparan los valores de dos objetos. Los objetos no necesitan tener el mismo tipo. Si ambos son números, se convierten a un tipo común.

Como consecuencia, False se convierte en un entero por la necesidad de la comparación. Pero es diferente de 0.

>>> 0 is False
False
luc
fuente
26
Esto no es del todo correcto: booles una subclase de int, por lo que, en un sentido muy real, un bool es un número entero. Por ejemplo, isinstance(True, int)devuelve True. Y la verificación de igualdad no convierte el bool en un int, ya que no es necesaria la conversión: simplemente llama int.__cmp__directamente. Tenga en cuenta que bool.__cmp__ is int.__cmp__también evalúa a True.
Mark Dickinson
3
-1 para esta respuesta. Descripción incorrecta de la relación entre bool e int (en Python 2). isinstance(True, int)=> Verdadero. Es decir, True ES un número entero y no requiere conversión.
ToolmakerSteve
Tenía un script que devolvía False o un Int ... usando while response is Falsetrabajado, y while response == Falseno ... ¡Gracias!
curly_brackets
55
Eso 0 is Falsees falso no te dice nada. En su intérprete interactivo, ingrese x = -10, luego y = -10, luego x is yy eso también será falso. El hecho de que existan optimizaciones en el lugar donde el intérprete de Python reutiliza los mismos objetos enteros en ciertas circunstancias (almacenar literales enteros como constantes, internos enteros pequeños) no significa que isdeba usarse cuando desee probar la igualdad del valor entero .
Martijn Pieters