Recabamos por diferentes foros para así tener para ti la solución para tu problema, si tienes alguna pregunta déjanos tu comentario y respondemos sin falta.
Solución:
El consejo no es que nunca debas usarTrue
, 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 true. Entonces cuando escribes if x == True
Python va a evaluar primero x == True
, que se convertirá en True
si x
era True
y False
de lo contrario, y luego proceda si el resultado de eso es true. Pero si estas esperando x
ser cualquiera True
o False
, ¿por qué no usar if x
¡directamente!
Igualmente, x == False
generalmente puede ser reemplazado por not x
.
Hay algunas circunstancias en las que es posible que desee utilizar x == True
. Esto es porque un if
la condición de la declaración se “evalúa en contexto booleano” para ver si es “veraz” en lugar de probarla exactamente contra True
. Por ejemplo, las cadenas, listas y diccionarios no vacíos se consideran veraces por una declaración if, así como valores numéricos distintos de cero, pero ninguno de ellos es igual a True
. Entonces, si desea probar si un valor arbitrario es exactamente el valor True
, no solo si es veraz, cuándo usarías if x == True
. Pero casi nunca veo un uso para eso. Es tan raro que si tu hacer alguna vez necesite escribir eso, vale la pena agregar un comentario para que los futuros desarrolladores (incluido posiblemente usted mismo) no solo asuman el == True
es superfluo y eliminarlo.
Utilizando x is True
en cambio, es peor. Nunca deberías usar is
con tipos inmutables integrados básicos como booleanos (True
, False
), números y cadenas. La razón es que para estos tipos nos preocupamos valores, no identidad. ==
prueba que los valores son los mismos para estos tipos, mientras que is
siempre prueba las identidades.
Probar identidades en lugar de valores es malo porque, en teoría, una implementación podría construir nuevos valores booleanos en lugar de buscar los existentes, lo que lleva a tener dos True
valores que tienen el mismo valor, pero que se almacenan en diferentes lugares de la memoria y tienen diferentes identidades. En la práctica estoy bastante seguro 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 molesta a la gente todo el tiempo con cadenas, porque Python recicla las cadenas cortas y las cadenas literales que aparecen directamente en la fuente del programa. 'foo' is 'foo'
siempre regresa True
. Pero es fácil construir lo mismo string 2 formas diferentes y haga que Python les dé diferentes identidades. Observe lo siguiente:
>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True
EDITAR: Entonces, resulta que la igualdad de Python en los booleanos es un poco inesperada (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 de esto, como se explica en las notas cuando se introdujeron bools en Python 2.3.5, es que el antiguo comportamiento de usar los enteros 1 y 0 para representar Verdadero y Falso era bueno, pero solo queríamos nombres más descriptivos para los números que pretendíamos para representar valores de verdad.
Una forma de lograrlo hubiera sido simplemente tener True = 1
y False = 0
en las incorporaciones; entonces 1 y True realmente serían indistinguibles (incluso por is
). Pero eso también significaría que una función regresa True
mostraría 1
en el intérprete interactivo, por lo que lo que se ha hecho en su lugar es crear bool
como subtipo de int
. Lo único que es diferente en bool
es str
y repr
; bool
las instancias todavía tienen los mismos datos que int
instancias, y aún comparar la igualdad de la misma manera, por lo que True == 1
.
Entonces está mal usar x is True
cuando x
podría haber sido establecido por algún código que espera que “Verdadero es solo otra forma de deletrear 1”, porque hay muchas formas de construir valores que son iguales a True
pero no tienen la misma identidad que él:
>>> 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 está mal usar x == True
cuando x
podría ser un valor de Python arbitrario y solo desea saber si es el valor booleano True
. La única certeza que tenemos es que con solo usar x
es mejor cuando solo desea probar la “veracidad”. Afortunadamente, eso suele ser todo lo que se requiere, ¡al menos en el código que escribo!
Una forma más segura sería x == True and type(x) is bool
. Pero eso se está volviendo bastante detallado para un caso bastante oscuro. Tampoco se ve muy Pythonic al hacer una verificación de tipo explícita … pero eso es realmente lo que estás haciendo cuando intentas probar con precisión True
en lugar de veracidad; la forma de escribir pato sería aceptar valores veraces y permitir que cualquier clase definida por el usuario se declare veraz.
Si está lidiando con esta noción de verdad extremadamente precisa en la que no solo no considera que las colecciones no vacías sean true pero tampoco consideres que 1 sea true, luego solo usa x is True
probablemente esté bien, porque presumiblemente entonces sabes que x
no provino de un código que considera que 1 es true. No creo que haya ninguna forma de pitón pura para pensar en otra True
que vive en una dirección de memoria diferente (aunque probablemente podría hacerlo desde C), por lo que esto nunca debería romperse a pesar de ser teóricamente lo “incorrecto”.
¡Y solía pensar que los booleanos eran simples!
Finalizar edición
En el caso de None
, sin embargo, el modismo es usar if x is None
. En muchas circunstancias puede utilizar if not x
, porque None
es un valor “falso” para un if
declaración. Pero es mejor hacer esto solo si desea tratar todos los valores falsey (tipos numéricos de valor cero, colecciones vacías y None
) de la misma manera. Si está tratando con un valor que es 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 usar if x is None
para que no asuma accidentalmente que la función falló cuando simplemente devolvió una lista vacía, o el número 0.
Mis argumentos para usar ==
en vez de is
para tipos de valores inmutables sugeriría que debería usar if x == None
en vez de if x is None
. Sin embargo, en el caso de None
Python garantiza explícitamente que hay exactamente uno None
en todo el universo, y el código Python idiomático normal utiliza is
.
Respecto a si regresar None
o plantear una excepción, depende del contexto.
Por algo como tu get_attr
ejemplo, esperaría que genere una excepción, porque lo voy a llamar como do_something_with(get_attr(file))
. La expectativa normal de las personas que llaman es que obtendrán la attribute valor, y hacer que obtengan None
y asumir que era el attribute El valor es un peligro mucho peor que olvidarse de manejar la excepción cuando realmente puede continuar si el attribute no se puede encontrar. Además, regresando None
indicar falla significa que None
no es un valor válido para el attribute. Esto puede ser un problema en algunos casos.
Para una función imaginaria como see_if_matching_file_exists
, al que proporcionamos un patrón y verifica varios lugares para ver si hay una coincidencia, podría devolver una coincidencia si encuentra una o None
si no es así. 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 recupero algo).
Entonces, al elegir entre excepciones y None
para indicar falla, debe decidir si None
es un valor esperado sin fallas, y luego observe las expectativas del código que llama a la función. Si la expectativa “normal” es que habrá un valor válido devuelto, y sólo ocasionalmente una persona que llama podrá trabajar bien independientemente de que se devuelva un valor válido o no, entonces debe usar excepciones para indicar falla. Si será bastante común que no haya un valor válido, por lo que las personas que llaman esperarán manejar ambas posibilidades, entonces puede usar None
.
Usar if foo
o if not foo
. No hay necesidad de ninguno ==
o is
para eso.
Para verificar con Ninguno, is None
y is not None
se recomiendan. Esto le permite distinguirlo de Falso (o cosas que se evalúan como Falso, como ""
y []
).
Si get_attr
debería volver None
Dependería del contexto. Es posible que tenga un attribute donde el valor es Ninguno, y no podría hacer eso. Yo interpretaría None
en el sentido de “no armado”, y un KeyError
significaría el key no existe en el archivo.
Si busca la verdad:
if foo
Para false:
if not foo
Para ninguno:
if foo is None
Para los que no son ninguno:
if foo is not None
Para getattr()
el comportamiento correcto es no regresar None
, pero levanta un AttributError
error en su lugar, a menos que su clase sea algo como defaultdict
.