none - python is not null




objeto nulo en Python? (4)

¿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:


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:
    ...




null