Objeto nulo en Python

15 minutos de lectura

avatar de usuario
Lagarto

¿Cómo me refiero a la objeto nulo en Python?

avatar de usuario
ben james

En Python, el objeto ‘nulo’ es el singleton None.

Para comprobar si algo es Noneutilizar el is operador de identidad:

if foo is None:
    ...

  • Y la razón de elegir egg is None sobre egg == None: Este último puede sobrecargarse y es probable que se rompa al comparar un objeto válido con Ninguno (depende de cómo se implemente, pero no espera que todos tomen en cuenta las comparaciones con Ninguno, ¿verdad?), Mientras que is siempre funciona igual.

    usuario395760

    20 de julio de 2010 a las 12:25

  • ¿Por qué los diseñadores de Python simplemente eligieron “null”? ¡Solo tienes que ser diferente, no es así! 😉

    – Vidar

    26 de marzo de 2013 a las 9:44

  • @Vidar ‘Ninguno’ no es la falta de un objeto (como lo es ‘nulo’, una referencia nula), es un objeto real. Nunca obtendrá un objeto ‘Ninguno’ que pasa por un objeto que es de un tipo diferente a ‘NoneType’. Tampoco es un concepto de lenguaje. No está integrado en el lenguaje Python, es parte de la biblioteca estándar de Python. Ninguno !== (ejem) Nulo

    – Rushyo

    12 de junio de 2013 a las 12:17

  • @ naught101 No serviría para nada; ya que no existe el concepto de punteros. Si está utilizando la biblioteca ctypes, Ninguno se utilizará como sinónimo de la dirección cero, pero aún no existe el concepto de lenguaje de una ‘referencia nula’. En Python, siempre se dejaba hacer referencia a algún tipo de objeto, incluso si ese objeto es Ninguno. Sospecho que esto simplifica enormemente el lenguaje.

    – Rushyo

    2 de septiembre de 2014 a las 13:26


  • gran presentación que explica el ‘error de mil millones de dólares’ que es la referencia nula: infoq.com/presentaciones/…. Otras opciones en lugar de nulo son Opciones o tipos Tal vez (personalizados).

    – Michael Trow

    08/04/2015 a las 23:56


avatar de usuario
miguel ekoka

NonePython es nulo?

No hay null en Python; en cambio hay None. Como ya se dijo, la forma más precisa de probar que algo se ha dado None como valor es usar el is operador de identidad, que prueba 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

None es la única instancia de la clase NoneType y cualquier otro intento de instanciar esa clase devolverá el mismo objeto, lo que hace que None un singleton Los recién llegados a Python a menudo ven mensajes de error que mencionan NoneType y me pregunto 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. Así que si ves algunos TypeError mensaje que menciona que NoneType no puede hacer esto o no puede hacer aquello, solo sepa que es simplemente el None que estaba siendo utilizado de una manera que no puede.

También, None es una constante incorporada. Tan pronto como inicie Python, estará disponible para su uso desde cualquier lugar, ya sea en el módulo, la clase o la función. NoneType por el contrario, no lo es, primero necesitaría obtener una referencia consultando None por su clase.

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

Puedes comprobar Nonela singularidad de con la función de identidad de Python id(). Devuelve el número único asignado a un objeto, cada objeto tiene uno. Si la identificación de dos variables es la misma, 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 se puede sobrescribir

En versiones mucho más antiguas de Python (antes de la 2.4) era posible reasignar None, pero ya no más. 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 todos None las referencias son las mismas. No hay ninguna “costumbre” None.

para probar None utilizar el is operador

Al escribir código, es posible que tenga la tentación de probar la nada como esto:

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

Por qué

value is None

más bien que

value==None

?

El primero es equivalente a:

id(value)==id(None)

Considerando que la expresión value==None de hecho se aplica así

value.__eq__(None)

Si el valor es realmente None entonces obtendrás lo que esperabas.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

En la mayoría de los casos comunes, el resultado será el mismo, pero el __eq__() El método abre una puerta que anula cualquier garantía de precisión, ya que puede anularse en una clase para proporcionar un comportamiento especial.

Considere esta clase.

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

Así que pruébalo None y funciona

>>> empty = Empty()
>>> empty==None
True

Pero luego también funciona en la cadena vacía.

>>> empty==''
True

Y todavía

>>> ''==None
False
>>> empty is None
False

Caso 2: Uso None como booleano

Las siguientes dos pruebas

if value:
    # Do something

if not value:
    # Do something

de hecho se evalúan como

if bool(value):
    # Do something

if not bool(value):
    # Do something

None es una “falsedad”, lo que significa que si se convierte en un valor booleano, devolverá False y si se aplica el not operador volverá True. Sin embargo, tenga en cuenta que no es una propiedad exclusiva de None. Además de False en sí misma, la propiedad es compartida por listas vacías, tuplas, conjuntos, dictados, cadenas, así como 0, y todos los objetos de las clases que implementan el __bool__() método mágico para volver 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

Entonces, cuando pruebe las variables de la siguiente manera, tenga mucho cuidado con lo que está incluyendo o excluyendo de la prueba:

def some_function(value=None):
    if not value:
        value = init_value()

En lo anterior, ¿quisiste llamar init_value() cuando el valor se establece específicamente en Noneo quiso decir que un valor establecido en 0, o la cadena vacía, o una lista vacía también debería desencadenar la inicialización? Como dije, ten cuidado. Como suele ser el caso, en Python explícito es mejor que implícito.

None en la práctica

None utilizado como un valor de señal

None tiene un estado especial en Python. Es un valor de referencia favorito porque muchos algoritmos lo tratan como un valor excepcional. En tales escenarios, se puede usar como una bandera para señalar que una condición requiere un manejo especial (como la configuración de un valor predeterminado).

Puedes asignar None a los argumentos de palabra clave de una función y luego probarla explícitamente.

def my_function(value, param=None):
    if param is None:
        # Do something outrageous!

Puede devolverlo como predeterminado cuando intente obtener el 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, un diccionario get() el método devuelve None al intentar acceder a una clave inexistente:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

Si intentara acceder a él usando la notación de subíndice a KeyError sería levantado

>>> value = some_dict['foo']
KeyError: 'foo'

Del mismo modo, si intenta abrir un elemento que no existe

>>> 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 indicador y como valor válido

Los usos antes descritos de None se aplica cuando no se considera un valor válido, sino más bien una señal para hacer algo especial. Sin embargo, hay situaciones en las que a veces importa saber dónde None vino 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) volviendo None no le dice si el atributo al que estaba tratando de acceder se configuró en None o si estaba completamente ausente del objeto. La misma situación al acceder a una clave de un diccionario, como some_dict.get('some_key')no sabes si some_dict['some_key'] falta o si solo está configurado para None. Si necesita esa información, la forma habitual de manejar esto es intentar acceder directamente al atributo o clave desde dentro de un try/except construir:

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 handling 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 palabra clave de doble asterisco 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 utilizado solo como un valor válido

Si encuentra que su código está lleno de lo anterior try/except patrón simplemente para diferenciar entre None banderas y None datos, luego simplemente use otro valor de prueba. Hay un patrón en el que un valor que queda 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.). Tal valor se llama centinela y se puede usar de la manera None se utiliza como señal. Es trivial crear un centinela en Python.

undefined = object()

los undefined objeto anterior es único y no hace mucho de nada que pueda ser de interés para un programa, por lo que es un excelente reemplazo para None como bandera Se aplican algunas advertencias, más sobre eso después del código.

Con función

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. En primer lugar, no son palabras clave como None, por lo que Python no los protege. Puede sobrescribir su undefined arriba en cualquier momento, en cualquier lugar del módulo que esté definido, así que tenga cuidado al exponerlos y usarlos. A continuación, la instancia devuelta por object() no es un singleton. Si haces esa llamada 10 veces obtienes 10 objetos diferentes. Finalmente, el uso de un centinela es altamente idiosincrático. Un centinela es específico de la biblioteca en la que se usa y, como tal, su alcance generalmente debe limitarse a las partes internas de la biblioteca. No debería “filtrarse”. El código externo solo debe conocerlo si su propósito es ampliar o complementar la API de la biblioteca.

  • ¿Qué pasa con: Ninguno == cosa?

    – hkBst

    1 de noviembre de 2018 a las 9:56

  • @hkBst Supongo que su pregunta es sobre cómo Python evalúa la igualdad. Eche un vistazo a este stackoverflow.com/questions/3588776/…

    – Michael Ekoka

    1 de noviembre de 2018 a las 17:02


  • Ah, entonces IIUC que por lo general terminará llamando a cosa.__eq__? En ese caso me retracto de mi sugerencia.

    – hkBst

    2 de noviembre de 2018 a las 9:56

  • @MichaelEkoka, ¿puede compartir la fuente de esta impresionante y útil información?

    – Anidhya Bhatnagar

    25 de diciembre de 2018 a las 6:46

  • Práctica estándar. Usted puede encontrar algunos indicios de ello al pasar por el Tutorial de Pythonpero leer el código fuente de proyectos populares es mi consejo número uno para sumergirse rápidamente en Python idiomático.

    – Michael Ekoka

    14 de abril de 2019 a las 5:53


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 == Nonesi tu quieres.

  • Voy a encontrar una manera de romper Python volviendo a crear instancias None. Entonces todas esas personas inteligentes que se compararon contra NoneType triunfará!

    – Zenexer

    27 de agosto de 2013 a las 3:40

En Python, para representar la ausencia de un valor, puede usar el Ninguna valor (tipos.NingunoTipo.Ninguno) para objetos y “” (o largo() == 0) para cadenas. Por lo tanto:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

Con respecto a la diferencia entre “==” y “is”, probar la identidad del objeto usando “==” 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:

Las respuestas anteriores solo resultarán True por Nonepero existe tal cosa como float('nan'). Podrías usar pandas isnull:

>>> import pandas as pd
>>> pd.isnull(None)
True
>>> pd.isnull(float('nan'))
True
>>> pd.isnull('abc')
False
>>> 

O sin pandas:

>>> a = float('nan')
>>> (a != a) or (a == None)
True
>>> a = None
>>> (a != a) or (a == None)
True
>>> 

La razón por la que esto funciona es porque float('nan') != float('nan'):

>>> float('nan') == float('nan')
False
>>> float('nan') != float('nan')
True
>>> 

avatar de usuario
s_mj

Usar f cadena para resolver esto.

year=None
year_val="null" if year is None else  str(year)
print(f'{year_val}')

null

Función simple para abordar el elemento “vacío” en Python:

Código:

def is_empty(element) -> bool:
    """
    Function to check if input `element` is empty.

    Other than some special exclusions and inclusions,
    this function returns boolean result of Falsy check.
    """
    if (isinstance(element, int) or isinstance(element, float)) and element == 0:
        # Exclude 0 and 0.0 from the Falsy set.
        return False
    elif isinstance(element, str) and len(element.strip()) == 0:
        # Include string with one or more empty space(s) into Falsy set.
        return True
    elif isinstance(element, bool):
        # Exclude False from the Falsy set.
        return False
    else:
        # Falsy check.
        return False if element else True

Prueba:

print("Is empty?\n")
print('"" -> ', is_empty(""))
print('"      " -> ', is_empty("      "))
print('"A" -> ', is_empty("A"))
print('"a" -> ', is_empty("a"))
print('"0" -> ', is_empty("0"))
print("0 -> ", is_empty(0))
print("0.0 -> ", is_empty(0.0))
print("[] -> ", is_empty([]))
print("{} -> ", is_empty({}))
print("() -> ", is_empty(()))
print("[1, 2] -> ", is_empty([1, 2]))
print("(3, 5) -> ", is_empty((3, 5)))
print('{"a": 1} -> ', is_empty({"a": 1}))
print("None -> ", is_empty(None))
print("True -> ", is_empty(True))
print("False -> ", is_empty(False))
print("NaN -> ", is_empty(float("nan")))
print("range(0) -> ", is_empty(range(0)))

Producción:

Is empty?

"" ->  True
"      " ->  True
"A" ->  False
"a" ->  False
"0" ->  False
0 ->  False
0.0 ->  False
[] ->  True
{} ->  True
() ->  True
[1, 2] ->  False
(3, 5) ->  False
{"a": 1} ->  False
None ->  True
True ->  False
False ->  False
NaN ->  False
range(0) ->  True

¿Ha sido útil esta solución?