Pregunta objeto nulo en Python?


¿Cómo me refiero al objeto nulo en Python?


804
2017-07-20 11:53


origen


Respuestas:


En Python, el objeto 'nulo' es el singleton None.

La mejor manera de verificar las cosas para "Noneness" es usar el operador de identidad, is:

if foo is None:
    ...

1119
2017-07-20 11:54



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


53
2017-07-20 11:56



En Python, para representar la ausencia de un valor, puede usar Ninguna valor (types.NoneType.None) para objetos y "" (o len () == 0) para cuerdas. Por lo tanto:

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

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

En cuanto a la diferencia entre "==" y "es", la prueba de 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:


26
2018-03-03 11:11



None, Null de Python?

No hay null en Python, en cambio hay None. Como ya se dijo, la forma más precisa de probar que se ha dado algo None como un 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 intento adicional de instanciar esa clase devolverá el mismo objeto, lo que hace 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 simplemente podrían mencionar None por nombre porque, como veremos en breve, None deja poco espacio a la ambigüedad. Entonces si ves algo TypeError mensaje que menciona eso NoneType no puedo hacer esto o no puedo hacer eso, solo sé que es simplemente el None que estaba siendo usado de una manera que no puede.

También, None es una constante incorporada, tan pronto como inicie Python está disponible para usar desde cualquier lugar, ya sea en módulo, clase o función. NoneType por el contrario no lo es, necesitarás obtener una referencia primero al consultar None para su clase.

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

Puedes comprobar NoneLa singularidad de Python con la función de identidad 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 señalan 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 una versión mucho más antigua de Python (antes 2.4) fue 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 todo None las referencias son iguales. No hay una "costumbre" None.

Para probar None utilizar el is operador

Al escribir el código, es posible que tengas la tentación de probarlo Inexistencia Me gusta esto:

if value==None:
    pass

O para probar falsedades como esta

if not value:
    pass

Necesita 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é 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 de esta manera

value.__eq__(None)

si el valor realmente es None entonces 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__() 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.

Considera esta clase.

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

Entonces lo intentas 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 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 volverá False y si aplica el not operador regresará True. Sin embargo, tenga en cuenta que no es una propiedad exclusiva de None. Además de False en sí, 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 regresar 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, al probar las variables de la siguiente manera, tenga en cuenta lo que está incluyendo o excluyendo de la prueba:

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

En el de arriba, ¿quisiste llamar init_value() cuando el valor se establece específicamente para None, o quiso decir que un valor establecido para 0, o la cadena vacía, o una lista vacía también debe 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 indicador para indicar que una condición requiere algún manejo especial (como la configuración de un valor predeterminado).

Puedes asignar None a la palabra clave argumentos de una función y luego explícitamente prueba para ello.

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

Puede devolverlo como predeterminado cuando intente acceder 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, un diccionario get() método devuelve None cuando intenta acceder a una clave no existente:

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

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

>>> 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 está configurado para 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 aplicar 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 dónde None vino porque aunque se usa como 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 intentaba acceder estaba configurado para 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 está configurado para None. Si necesita esa información, la forma habitual de manejar esto es intentar directamente acceder 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 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é ocurre 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 válido

Si encuentra que su código está lleno de los anteriores 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 puede ser usado de la manera None se usa como una señal. Es trivial crear un centinela en Python.

undefined = object()

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

Con la 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. Primero, no son palabras clave como None, entonces Python no los protege. Puedes sobreescribir tu undefined arriba en cualquier momento, en cualquier parte del módulo que esté definido, así que tenga cuidado de cómo los expone y usa. 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ásico. Un centinela es específico de la biblioteca en la que se utiliza 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.


26
2018-01-29 15:34



Por Prueba de valor de verdad, 'Ninguno' prueba directamente como FALSO, por lo que la expresión más simple será suficiente:

if not foo:

0
2017-09-24 23:15