none - objeto nulo en Python?
null string python (5)
¿Cómo me refiero al objeto nulo en Python?
None
, nulo de Python?
No hay null
en Python, en cambio no hay None
. Como ya se dijo, la forma más precisa de probar que algo se ha dado a None
como valor es usar el operador de identidad, que comprueba que dos variables se refieren al mismo objeto.
>>> foo is None
True
>>> foo = ''bar''
>>> foo is None
False
Los basicos
Hay y solo puede haber uno.
None
es la única instancia de la clase NoneType
y cualquier intento posterior de crear una instancia de esa clase devolverá el mismo objeto, lo que hace que None
sea un singleton. Los recién llegados a Python a menudo ven mensajes de error que mencionan NoneType
y se preguntan qué es. Es mi opinión personal que estos mensajes podrían simplemente mencionar None
por su nombre porque, como veremos en breve, None
deja poco espacio a la ambigüedad. Por lo tanto, si ve algún mensaje de error de tipo que menciona que NoneType
no puede hacer esto o no puede hacerlo, simplemente sepa que es simplemente el NoneType
None
que se estaba usando de una manera que no puede.
Además, None
es una constante incorporada, tan pronto como inicias Python está disponible para usar desde cualquier lugar, ya sea en módulo, clase o función. NoneType
Por el contrario, el tipo de texto no lo es, primero debe obtener una referencia a él consultando la clase de None
.
>>> NoneType
NameError: name ''NoneType'' is not defined
>>> type(None)
NoneType
Puede verificar la singularidad de None
con la función de identidad de Python id()
. Devuelve el número único asignado a un objeto, cada objeto tiene uno. Si el identificador de dos variables es el mismo, entonces apuntan de hecho al mismo objeto.
>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000
None
no puede ser sobrescrito
En una versión mucho más antigua de Python (antes de la 2.4) era posible reasignar None
, pero ya no. Ni siquiera como un atributo de clase o en los límites de una función.
# In Python 2.7
>>> class SomeClass(object):
... def my_fnc(self):
... self.None = ''foo''
SyntaxError: cannot assign to None
>>> def my_fnc():
None = ''foo''
SyntaxError: cannot assign to None
# In Python 3.5
>>> class SomeClass:
... def my_fnc(self):
... self.None = ''foo''
SyntaxError: invalid syntax
>>> def my_fnc():
None = ''foo''
SyntaxError: cannot assign to keyword
Por lo tanto, es seguro asumir que todas las referencias de None
son iguales. No hay ninguna "costumbre".
Para probar para None
usar el operador is
Cuando escribes un código, puedes tener la tentación de probar la noidad de esta manera:
if value==None:
pass
O para probar la falsedad como esta.
if not value:
pass
Debe comprender las implicaciones y por qué a menudo es una buena idea ser explícito.
Caso 1: probar si un valor es None
porque hacer esto
value is None
más bien que
value==None
El primero es equivalente a:
id(value)==id(None)
Mientras que la expresión value==None
de hecho, se aplica así
value.__eq__(None)
Si el valor realmente es None
, obtendrás lo que esperabas.
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
En la mayoría de los casos, el resultado será el mismo, pero el __eq__()
abre una puerta que anula cualquier garantía de precisión, ya que se puede anular en una clase para proporcionar un comportamiento especial.
Considera esta clase.
>>> class Empty(object):
... def __eq__(self, other):
... return not other
Así que lo intentas en None
y funciona.
>>> empty = Empty()
>>> empty==None
True
Pero entonces también funciona en la cadena vacía.
>>> empty==''''
True
Y todavía
>>> ''''==None
False
>>> empty is None
False
Caso 2: Usando None
como booleano
Las siguientes dos pruebas
if value:
# do something
if not value:
# do something
de hecho son evaluados como
if bool(value):
# do something
if not bool(value):
# do something
None
es un "falsey", lo que significa que si se lanza a un booleano devolverá False
y si se aplica el operador no, devolverá True
. Sin embargo, tenga en cuenta que no es una propiedad exclusiva de None
. Además de False
, la propiedad se comparte mediante listas vacías, tuplas, conjuntos, dicts, cadenas, así como 0, y todos los objetos de las clases que implementan el método mágico __bool__()
para devolver False
.
>>> bool(None)
False
>>> not None
True
>>> bool([])
False
>>> not []
True
>>> class MyFalsey(object):
... def __bool__(self):
... return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True
Por lo tanto, cuando realice pruebas de variables de la siguiente manera, tenga más conciencia de lo que está incluyendo o excluyendo de la prueba:
def some_function(value=None):
if not value:
value = init_value()
En lo anterior, ¿quiso usted llamar a init_value()
cuando el valor se estableció específicamente en None
, o quiso decir que un valor establecido en 0
, o la cadena vacía, o una lista vacía también debería activar la inicialización? Como dije antes, se atento. Como suele ser el caso, en Python explícito es mejor que implícito .
None
en practica
None
usado como valor de señal
None
tiene un estado especial en Python. Es un valor de línea de base favorito porque muchos algoritmos lo consideran un valor excepcional. En tales escenarios, se puede utilizar como un indicador para indicar que una condición requiere un manejo especial (como la configuración de un valor predeterminado).
Puede asignar None
a los argumentos de palabra clave de una función y luego probarlos explícitamente.
def my_function(value, param=None):
if param is None:
# do something outrageous!
Puede devolverlo como el valor predeterminado al intentar llegar al atributo de un objeto y luego probarlo explícitamente antes de hacer algo especial.
value = getattr(some_obj, ''some_attribute'', None)
if value is None:
# do something spectacular!
Por defecto, el método get()
un diccionario devuelve None
cuando se intenta acceder a una clave que no existe:
>>> some_dict = {}
>>> value = some_dict.get(''foo'')
>>> value is None
True
Si intentara acceder a él utilizando la notación de KeyError
se KeyError
un KeyError
>>> value = some_dict[''foo'']
KeyError: ''foo''
Del mismo modo, si intenta hacer estallar un elemento no existente
>>> value = some_dict.pop(''foo'')
KeyError: ''foo''
que puede suprimir con un valor predeterminado que generalmente se establece en None
value = some_dict.pop(''foo'', None)
if value is None:
# booom!
None
utilizado como bandera y valor válido
Los usos descritos anteriormente de None
aplican cuando no se considera un valor válido, sino más bien como una señal para hacer algo especial. Sin embargo, hay situaciones en las que a veces es importante saber de dónde vino None
porque, aunque se usa como una señal, también podría ser parte de los datos.
Cuando consulta un objeto por su atributo con getattr(some_obj, ''attribute_name'', None)
volver atrás None
no le dice si el atributo al que estaba intentando acceder estaba configurado como None
o si estaba totalmente ausente del objeto. La misma situación al acceder a una clave de un diccionario como some_dict.get(''some_key'')
, no se sabe si some_dict[''some_key'']
o si simplemente está configurado en None
. Si necesita esa información, la forma habitual de manejar esto es intentar acceder directamente al atributo o clave desde una construcción try/except
:
try:
# equivalent to getattr() without specifying a default
# value = getattr(some_obj, ''some_attribute'')
value = some_obj.some_attribute
# now you handle `None` the data here
if value is None:
# do something here because the attribute was set to None
except AttributeError:
# we''re now hanling the exceptional situation from here.
# We could assign None as a default value if required.
value = None
# In addition, since we now know that some_obj doesn''t have the
# attribute ''some_attribute'' we could do something about that.
log_something(some_obj)
Del mismo modo con dict:
try:
value = some_dict[''some_key'']
if value is None:
# do something here because ''some_key'' is set to None
except KeyError:
# set a default
value = None
# and do something because ''some_key'' was missing
# from the dict.
log_something(some_dict)
Los dos ejemplos anteriores muestran cómo manejar casos de objetos y diccionarios, ¿qué pasa con las funciones? Lo mismo, pero usamos el argumento de la palabra clave asteriscos dobles para ese fin:
def my_function(**kwargs):
try:
value = kwargs[''some_key'']
if value is None:
# do something because ''some_key'' is explicitly
# set to None
except KeyError:
# we assign the default
value = None
# and since it''s not coming from the caller.
log_something(''did not receive "some_key"'')
None
usado solo como un valor valido
Si encuentra que su código está lleno del patrón de try/except
simplemente para diferenciar entre las banderas None
y la información None
, entonces solo use otro valor de prueba. Hay un patrón donde un valor que cae fuera del conjunto de valores válidos se inserta como parte de los datos en una estructura de datos y se usa para controlar y probar condiciones especiales (por ejemplo, límites, estado, etc.). Dicho valor se denomina centinela y se puede usar de la forma en que se usa None
como señal. Es trivial crear un centinela en Python.
undefined = object()
El objeto undefined
arriba es único y no hace nada de lo que pueda ser de interés para un programa, por lo que es un excelente reemplazo para None
como indicador. Algunas advertencias se aplican, más sobre eso después del código.
Con funcion
def my_function(value, param1=undefined, param2=undefined):
if param1 is undefined:
# we know nothing was passed to it, not even None
log_something(''param1 was missing'')
param1 = None
if param2 is undefined:
# we got nothing here either
log_something(''param2 was missing'')
param2 = None
Con dict
value = some_dict.get(''some_key'', undefined)
if value is None:
log_something("''some_key'' was set to None")
if value is undefined:
# we know that the dict didn''t have ''some_key''
log_something("''some_key'' was not set at all")
value = None
Con un objeto
value = getattr(obj, ''some_attribute'', undefined)
if value is None:
log_something("''obj.some_attribute'' was set to None")
if value is undefined:
# we know that there''s no obj.some_attribute
log_something("no ''some_attribute'' set on obj")
value = None
Como mencioné anteriormente, los centinelas personalizados vienen con algunas advertencias. Primero, no son palabras clave como None
, por lo que Python no las protege. Puede sobrescribir su undefined
arriba en cualquier momento, en cualquier parte del módulo en el que esté definido, así que tenga cuidado de cómo los expone y los usa. A continuación, la instancia devuelta por object()
no es un singleton, si realiza esa llamada 10 veces, obtiene 10 objetos diferentes. Finalmente, el uso de un centinela es altamente idiosincrásico. Un centinela es específico de la biblioteca en la que se usa y, por lo tanto, su alcance generalmente debe limitarse a los aspectos internos de la biblioteca. No debería "escaparse". El código externo solo debe conocerlo, si su propósito es extender o complementar la API de la biblioteca.
En Python, para representar la ausencia de un valor, puede usar el valor Ninguno ( types.NoneType.None ) para los objetos y "" (o len () == 0 ) para las cadenas. Por lo tanto:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
Con respecto a la diferencia entre "==" y "es", la prueba de la identidad del objeto con "==" debería ser suficiente. Sin embargo, dado que la operación "es" se define como la operación de identidad del objeto, probablemente sea más correcto usarla, en lugar de "==". No estoy seguro si hay incluso una diferencia de velocidad.
De todos modos, puedes echar un vistazo a:
- Página de documento de constantes incorporadas de Python.
- Python Truth Value Testing página de documentos.
La prueba de valor de Verdad , ''Ninguna'' prueba directamente como FALSO, por lo que la expresión más simple será suficiente:
if not foo:
No se llama nulo como en otros idiomas, pero None
. Siempre hay una sola instancia de este objeto, por lo que puede verificar la equivalencia con x is None
(comparación de identidad) en lugar de x == None
, si lo desea.
En Python, el objeto ''nulo'' es el singleton None
.
La mejor manera de verificar las cosas para "No ser unidas" es usar el operador de identidad, is
:
if foo is None:
...