He visto varios ejemplos de código como este:
if not someobj:
#do something
Pero me pregunto por qué no hacer:
if someobj == None:
#do something
¿Hay alguna diferencia? ¿Uno tiene una ventaja sobre el otro?
X != None?
He visto varios ejemplos de código como este:
if not someobj:
#do something
Pero me pregunto por qué no hacer:
if someobj == None:
#do something
¿Hay alguna diferencia? ¿Uno tiene una ventaja sobre el otro?
X != None?
Respuestas:
En la primera prueba, Python intenta convertir el objeto a un boolvalor si aún no lo es. Aproximadamente, le preguntamos al objeto: ¿tiene sentido o no? Esto se hace usando el siguiente algoritmo:
Si el objeto tiene un __nonzero__método especial (como los incorporados numéricos, inty float), llama a este método. Debe devolver un boolvalor que luego se usa directamente, o un intvalor que se considera Falsesi es igual a cero.
De lo contrario, si el objeto tiene un __len__método especial (al igual que los contenedores empotrados, list, dict, set, tuple, ...), se llama a este método, teniendo en cuenta un contenedor Falsesi está vacío (longitud es cero).
De lo contrario, se considera el objeto a Truemenos que sea Noneen cuyo caso, se considera False.
En la segunda prueba, el objeto se compara por igualdad con None. Aquí, le preguntamos al objeto: "¿Eres igual a este otro valor?" Esto se hace usando el siguiente algoritmo:
Si el objeto tiene un __eq__método, se llama y el valor de retorno se convierte en un boolvalor y se utiliza para determinar el resultado de if.
De lo contrario, si el objeto tiene un __cmp__método, se llama. Esta función debe devolver una intindicación del orden de los dos objetos ( -1if self < other, 0if self == other, +1if self > other).
De lo contrario, los objetos se comparan por identidad (es decir, son referencias al mismo objeto, como puede ser probado por el isoperador).
Hay otra prueba posible usando el isoperador. Le estaríamos preguntando al objeto: "¿Eres este objeto en particular?"
En general, recomendaría usar la primera prueba con valores no numéricos, para usar la prueba de igualdad cuando desee comparar objetos de la misma naturaleza (dos cadenas, dos números, ...) y verificar la identidad solo cuando usando valores centinela (es Nonedecir, no inicializado para un campo miembro por ejemplo, o cuando se usan getattrlos __getitem__métodos o ).
Para resumir, tenemos:
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
Estas son en realidad ambas malas prácticas. Érase una vez, se consideró correcto tratar casualmente None y False como similares. Sin embargo, desde Python 2.2 esta no es la mejor política.
En primer lugar, cuando se hace una if xo if not xtipo de prueba, Python tiene para convertir implícitamente xa booleano. Las reglas para la boolfunción describen una serie de cosas que son falsas; todo lo demás es verdad. Si el valor de x no era adecuadamente booleano para empezar, esta conversión implícita no es realmente la forma más clara de decir las cosas.
Antes de Python 2.2, no había una función bool, por lo que era aún menos clara.
En segundo lugar, no deberías probar con == None. Deberías usar is Noney is not None.
Consulte PEP 8, Guía de estilo para el código Python .
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
¿Cuántos singletons hay? Cinco: None, True, False, NotImplementedy Ellipsis. Dado que es muy poco probable que use NotImplementedo Ellipsis, y nunca diría if x is True(porque simplemente if xes mucho más claro), solo lo probará None.
Porque Noneno es lo único que se considera falso.
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False, 0, (), [], {}Y ""son todas diferentes None, por lo que sus dos fragmentos de código son no equivalentes.
Además, considere lo siguiente:
>>> False == 0
True
>>> False == ()
False
if object:No es un control de igualdad. 0, (), [], None, {}, Etc son todas diferentes entre sí, pero todos ellos evalúan como False.
Esta es la "magia" detrás de expresiones de cortocircuito como:
foo = bar and spam or eggs
que es la abreviatura de:
if bar:
foo = spam
else:
foo = eggs
aunque realmente deberías escribir:
foo = spam if bar else egg
PEP 8: la guía de estilo para el código Python recomienda usar es o no si está probando la ausencia de ninguno
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
Por otro lado, si está probando más de None-ness, debe utilizar el operador booleano
Si preguntas
if not spam:
print "Sorry. No SPAM."
Se llama al método __nonzero__ de spam . Del manual de Python:
__nonzero__ ( self ) Llamado para implementar pruebas de valor de verdad y la operación incorporada bool (); debe devolver False o True, o sus equivalentes enteros 0 o 1. Cuando este método no está definido, se llama a __len __ (), si está definido (ver más abajo). Si una clase no define __len __ () ni __nonzero __ (), todas sus instancias se consideran verdaderas.
Si preguntas
if spam == None:
print "Sorry. No SPAM here either."
la __eq__ método de correo no deseado es llamado con el argumento Ninguno .
Para obtener más información sobre las posibilidades de personalización, consulte la documentación de Python en https://docs.python.org/reference/datamodel.html#basic-customization
Estas dos comparaciones tienen diferentes propósitos. El primero verifica el valor booleano de algo, el segundo verifica la identidad con el valor Ninguno.
La respuesta es, depende".
Utilizo el primer ejemplo si considero que 0, "", [] y False (la lista no es exhaustiva) son equivalentes a None en este contexto.
Personalmente, elegí un enfoque coherente en todos los idiomas: lo hago if (var)(o equivalente) solo si var se declara como booleano (o se define como tal, en C no tenemos un tipo específico). Incluso prefijo estas variables con un b(por lo que sería en bVarrealidad) para asegurarme de que no usaré accidentalmente otro tipo aquí.
Realmente no me gusta el casting implícito a booleano, mucho menos cuando hay numerosas reglas complejas.
Por supuesto, la gente no estará de acuerdo. Algunos van más allá, veo if (bVar == true)en el código de Java en mi trabajo (¡demasiado redundante para mi gusto!), A otros les encanta la sintaxis compacta, ir while (line = getNextLine())(demasiado ambiguo para mí).