lenguaje - python wikipedia
¿Por qué es "if not someobj:" better than "if someobj== None:" en Python? (9)
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?
En la primera prueba, Python intenta convertir el objeto a un valor bool
si aún no es uno. Aproximadamente, estamos preguntando el objeto: ¿tienes sentido o no? Esto se hace usando el siguiente algoritmo:
Si el objeto tiene un método especial
__nonzero__
(como lo hacen los complementos numéricos,int
yfloat
), llama a este método. Debe devolver un valorbool
que luego se usa directamente, o un valorint
que se consideraFalse
si es igual a cero.De lo contrario, si el objeto tiene un método especial
__len__
(como lo hacen los contenedores integrados,list
,dict
,set
,tuple
, ...), llama a este método, considerando un contenedorFalse
si está vacío (la longitud es cero).De lo contrario, el objeto se considera
True
menos que seaNone
en cuyo caso, se consideraFalse
.
En la segunda prueba, el objeto se compara por igualdad con None
. Aquí, estamos preguntando al objeto, "¿Eres igual a este otro valor?" Esto se hace usando el siguiente algoritmo:
Si el objeto tiene un método
__eq__
, se llama y el valor de retorno se convierte a un valorbool
y se usa para determinar el resultado delif
.De lo contrario, si el objeto tiene un método
__cmp__
, se llama. Esta función debe devolver unint
indique el orden de los dos objetos (-1
siself < other
,0
siself == other
,+1
siself > other
).De lo contrario, el objeto se compara con la identidad (es decir, son referencias al mismo objeto, como puede probar el operador
is
).
Hay otra prueba posible usando el operador is
. Le estaríamos preguntando al objeto, "¿Eres este objeto en particular?"
En general, recomendaría utilizar la primera prueba con valores no numéricos, usar la prueba de igualdad cuando desee comparar objetos de la misma naturaleza (dos cadenas, dos números, ...) y verificar la identidad solo cuando utilizando valores centinela ( None
significa que no se ha inicializado para un campo miembro por ejemplo, o cuando se usan los getattr
o __getitem__
).
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
En realidad, ambas son prácticas deficientes. Hubo un tiempo en que se consideraba aceptable tratar casualmente Ninguno y Falso como similares. Sin embargo, desde Python 2.2 esta no es la mejor política.
Primero, cuando haces un tipo de prueba if x
o if not x
, Python tiene que convertir implícitamente x
a boolean. Las reglas para la función bool
describen una gran cantidad de cosas que son falsas; todo lo demás es Verdadero Si el valor de x no era propiamente booleano para empezar, esta conversión implícita no es realmente la forma más clara de decir cosas.
Antes de Python 2.2, no había función bool, por lo que era aún menos claro.
En segundo lugar, no debería realmente probar con == None
. Deberías usar is None
y is not None
.
Ver PEP 8, Guía de estilo para el código de 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 singleton hay? Cinco: None
, True
, False
, no NotImplemented
y Ellipsis
. Dado que es poco probable que use NotImplemented
o Ellipsis
, y nunca diría if x is True
(porque simplemente if x
es mucho más claro), solo probará None
.
Estas dos comparaciones sirven para diferentes propósitos. El primero verifica el valor booleano de algo, el segundo comprueba la identidad con el valor Ninguno.
La respuesta es, depende".
Utilizo el primer ejemplo si considero que 0, "", [] y False (lista no exhaustiva) son equivalentes a Ninguno en este contexto.
Para uno, el primer ejemplo es más corto y se ve mejor. Según las otras publicaciones, lo que elijas también depende de lo que realmente quieras hacer con la comparación.
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 una b
(por lo que sería bVar
realidad) para asegurarme de que no bVar
accidentalmente otro tipo aquí.
Realmente no me gusta la conversión implícita a boolean, incluso menos cuando hay numerosas reglas complejas.
Por supuesto, las personas estarán en desacuerdo. Algunos van más allá, veo if (bVar == true)
en el código Java en mi trabajo (¡demasiado redundante para mi gusto!), Otros adoran demasiada sintaxis compacta, yendo while (line = getNextLine())
(demasiado ambiguo para mí )
Porque None
no 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 todos diferentes de None
, por lo que los dos fragmentos de código no son equivalentes.
Por otra parte, considere lo siguiente:
>>> False == 0
True
>>> False == ()
False
if object:
no es una verificación de igualdad. 0
, ()
, []
, None
, {}
, etc. son todos diferentes entre sí, pero todos evalúan a Falso.
Esta es la "magia" detrás de las 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
Si preguntas
if not spam:
print "Sorry. No SPAM."
se llama al método de spam __nonzero__ . Del manual de Python:
__nonzero__ ( self ) Invocado para implementar la prueba del valor de verdad, y la operación incorporada bool (); debería devolver False o True, o sus enteros equivalentes 0 o 1. Cuando este método no está definido, se llama a __len __ (), si está definido (ver a continuación). Si una clase no define ni __len __ () ni __nonzero __ (), todas sus instancias se consideran verdaderas.
Si preguntas
if spam == None:
print "Sorry. No SPAM here either."
se llama al método __eq__ de correo no deseado con el argumento Ninguno .
Para obtener más información sobre las posibilidades de personalización, eche un vistazo a la documentación de Python en https://docs.python.org/reference/datamodel.html#basic-customization
PEP 8: la Guía de estilo para el código de Python recomienda usar es o no es si está probando la inexistencia
- 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 usar el operador booleano.