El consejo no es que nunca se debe usoTrue
, False
o None
. Es solo que no deberías usar if x == True
.
if x == True
es tonto porque ==
es solo un operador binario! Tiene un valor de retorno de True
o False
, dependiendo de si sus argumentos son iguales o no. Y if condition
procederá si condition
es verdadero. Por lo tanto, cuando escriba if x == True
Python va a evaluar primero x == True
, que se convertirá en si x
fue y False
en caso contrario, y luego proceder si el resultado es cierto. Pero si espera que x
sea True
o False
, ¿por qué no simplemente usa if x
directamente?
Del mismo modo, x == False
generalmente puede ser reemplazado por not x
.
Hay algunas circunstancias en las que es posible que desee utilizar x == True
. Esto se debe a que una condición de enunciado if
se "evalúa en contexto booleano" para ver si es "veraz" en lugar de probar exactamente en contra de True
. Por ejemplo, las cadenas, listas y diccionarios no vacíos son considerados como verdad por una instrucción if, así como por valores numéricos distintos de cero, pero ninguno de ellos es igual a True
. Por lo tanto, si desea probar si un valor arbitrario es exactamente el valor True
, no solo si es cierto, cuándo usaría if x == True
. Pero casi nunca veo un uso para eso. Es tan raro que si hace alguna vez necesita escribir eso, vale la pena agregar un comentario para que los futuros desarrolladores (incluido posiblemente usted mismo) no asuman simplemente que el == True
es superfluo y lo elimine.
En su lugar, el uso de x is True
es peor. Nunca debe usar is
con tipos inmutables incorporados básicos como booleanos (True
, False
), números y cadenas. La razón es que para estos tipos nos importan valores, no identidad. ==
prueba que los valores son los mismos para estos tipos, mientras que is
siempre prueba identidades.
Probando identidades en lugar de valores es malo porque una implementación podría teóricamente construir nuevos valores booleanos en lugar de buscar los existentes, lo que lleva a tener dos valores True
que tienen el mismo valor pero se almacenan en diferentes lugares en la memoria y tienen diferentes identidades En la práctica, estoy bastante seguro de que True
y False
siempre son reutilizados por el intérprete de Python por lo que esto no sucederá, pero eso es realmente un detalle de implementación. Este problema desplaza a la gente todo el tiempo con cadenas, ya que las cadenas cortas y cadenas literales que aparecen directamente en el origen del programa son recicladas por Python para que 'foo' is 'foo'
siempre devuelva True
. Pero es fácil construir la misma cadena de 2 formas diferentes y Python les da diferentes identidades. Observe lo siguiente:
>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True
EDIT: Así que resulta que la igualdad de Python en booleanos es un poco inesperado (al menos para mí):
>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True
La razón para esto, como se explica en the notes when bools were introduced in Python 2.3.5, es que el antiguo comportamiento de usar enteros 1 y 0 para representar True y False era bueno, pero solo queríamos nombres más descriptivos para los números que pretendíamos representar valores de verdad.
Una forma de lograr eso habría sido simplemente tener True = 1
y False = 0
en los builtins; entonces 1 y Verdadero realmente serían indistinguibles (incluso por is
). Pero eso también significaría que una función que devuelve True
mostraría 1
en el intérprete interactivo, por lo que lo que se ha hecho en su lugar es crear bool
como un subtipo de int
. Lo único diferente de bool
es str
y repr
; Las instancias bool
todavía tienen los mismos datos que las instancias int
, y todavía comparan la igualdad de la misma manera, por lo que True == 1
.
Por lo que es incorrecto utilizar x is True
cuando x
podrían haber sido establecido por un código que espera que "la verdadera es más que otra forma de deletrear 1", porque hay un montón de maneras de construir valores que son iguales a True
pero no lo hacen tienen la misma identidad que es:
>>> a = 1L
>>> b = 1L
>>> c = 1
>>> d = 1.0
>>> a == True, b == True, c == True, d == True
(True, True, True, True)
>>> a is b, a is c, a is d, c is d
(False, False, False, False)
y es incorrecto utilizar x == True
cuando x
podría suponer un valor arbitrario de Python y sólo desea saber si es el valor booleano True
. La única certeza que tenemos es que solo usando x
es mejor cuando solo quieres probar la "veracidad". ¡Afortunadamente eso es todo lo que se requiere, al menos en el código que escribo!
Una manera más segura sería x == True and type(x) is bool
. Pero eso es bastante detallado para un caso bastante oscuro. Tampoco se ve muy pitónico haciendo una comprobación de tipos explícita ... pero eso es lo que estás haciendo cuando intentas probar con precisión True
en lugar de decir la verdad; la manera de tipar pato sería aceptar valores verdaderos y permitir que cualquier clase definida por el usuario se declare veraz.
Si está tratando con esta noción extremadamente precisa de la verdad, en la que no solo considera que las colecciones no vacías son ciertas, sino que también considera que 1 no es verdadero, entonces solo está usando x is True
, porque, presumiblemente, entonces usted sabe que x
no provino del código que considera que 1 es verdadero. No creo que haya una forma pura de pitón para encontrar otra True
que viva en una dirección de memoria diferente (aunque probablemente podrías hacerlo desde C), así que esto nunca debería romperse a pesar de ser teóricamente lo "incorrecto" que hacer.
¡Y solía pensar que los booleanos eran simples!
Fin Editar
En el caso de None
, sin embargo, el lenguaje es el uso de if x is None
. En muchas circunstancias, puede usar if not x
, porque None
es un valor "falsey" en una declaración if
. Pero lo mejor es hacer esto solo si quiere tratar todos los valores de falsey (tipos numéricos de cero valor, colecciones vacías y None
) de la misma manera. Si está tratando con un valor que sea algún otro valor posible o None
para indicar "sin valor" (como cuando una función devuelve None
en caso de falla), entonces es mucho mejor para usar if x is None
para no accidentalmente asumir la función falló cuando acaba de pasar a devolver una lista vacía, o el número 0.
Mis argumentos para utilizar ==
en lugar de is
de los tipos de valores inmutables que sugiere que se debe utilizar en lugar de if x == None
if x is None
. Sin embargo, en el caso de None
Python garantiza explícitamente que hay exactamente un None
en todo el universo, y el código de Python idiomático normal usa is
.
En cuanto a si se debe devolver None
o elevar una excepción, que depende del contexto.
Para algo así como su ejemplo get_attr
, esperaría que se produjera una excepción, porque la llamaré como do_something_with(get_attr(file))
.La expectativa normal de las personas que llaman es que obtendrán el valor del atributo, y que obtengan None
y asuman que el valor del atributo es mucho más peligroso que olvidarse de manejar la excepción cuando realmente se puede continuar si el atributo no puede ser encontrado. Además, devolver None
para indicar la falla significa que None
no es un valor válido para el atributo. Esto puede ser un problema en algunos casos.
Para una función imaginaria como see_if_matching_file_exists
, que proporcionamos un patrón y comprueba varios lugares para ver si hay una coincidencia, podría devolver una coincidencia si encuentra uno o None
si no lo hace. Pero alternativamente podría devolver una lista de coincidencias; entonces ninguna coincidencia es solo la lista vacía (que también es "falsey"; esta es una de esas situaciones en las que simplemente usaría if x
para ver si obtengo algo).
Por lo tanto, al elegir entre excepciones y None
para indicar una falla, debe decidir si None
es un valor esperado de no falla, y luego observar las expectativas del código que llama a la función. Si la expectativa "normal" es que se devolverá un valor válido, y solo ocasionalmente la persona que llama podrá trabajar bien si se devuelve o no un valor válido, entonces debe usar excepciones para indicar la falla. Si será bastante común que no exista un valor válido, entonces las personas que llaman esperarán manejar ambas posibilidades, luego puede usar None
.
Gracias por esta respuesta. Aclaró una cantidad de conceptos erróneos que he tenido durante bastante tiempo y aclaró algunos otros puntos que estaban un poco nublados. Pensé que Verdadero y Falso eran como Ninguno en esa serpiente pitón que garantizaba que sus identificaciones siempre serían las mismas. Lamentablemente, esto significa que tengo un montón de código para ver (grep) a través de ... – Vorticity
@Vorticity: para ser sincero, Python posiblemente * garantice * que sus identificaciones sean siempre las mismas, e incluso si no garantiza que estoy 99% seguro de que siempre serán las mismas en la práctica. Por lo tanto, no necesariamente me apresuro a editar 'x is True' fuera de todo tu código si tienes cosas mejores que hacer (como escribir un nuevo código :)). Pero en general, solo desea utilizar pruebas 'is' con objetos mutables (o' None', que es la excepción que prueba la regla). – Ben
Después de pensar en esto un poco más, tengo una pregunta. ¿Cómo se puede diferenciar entre una variable que contiene 'int (13)' y una que contiene 'True'? ¿Es solo que normalmente no te importa si la variable es realmente "Verdadera" y solo que es verdad? Supongo que estoy preguntando esto porque tengo que analizar de un lado a otro un formato de archivo molesto que contiene '' sí '' y '' no '' por todas partes, pero cuando en mi código prefiero estar tratar con 'True' y' False', así que tuve que escribir código para ir de uno a otro con un mínimo de alboroto. – Vorticity