2011-02-12 19 views
163

En C# hay un null-coalescing operator (escrito como ??) que permite la fácil (corto) comprobación nula durante la asignación:¿Hay un equivalente Python del operador C# nulo-coalescente?

string s = null; 
var other = s ?? "some default value"; 

¿Hay una pitón equivalente?

sé que puedo hacer:

s = None 
other = s if s else "some default value" 

Pero hay una manera aún más corto (en el que no necesito repetir s)?

+5

El operador '??' se propone como [PEP 505] (https://www.python.org/dev/peps/pep-0505/). –

Respuesta

248
other = s or "some default value" 

Vale, debe aclararse cómo funciona el operador or. Es un operador booleano, por lo que funciona en un contexto booleano. Si los valores no son booleanos, se convierten en booleanos para los fines del operador.

Tenga en cuenta que el operador or no devuelve solo True o False. En cambio, devuelve el primer operando si el primer operando se evalúa como verdadero, y devuelve el segundo operando si el primer operando se evalúa como falso.

En este caso, la expresión x or y devuelve x si es True o se evalúa como verdadero cuando se convierte a booleano. De lo contrario, devuelve y. Para la mayoría de los casos, esto servirá para el mismo fin del operador nulo coalescencia de C♯, pero tenga en cuenta:

42 or "something" # returns 42 
0  or "something" # returns "something" 
None or "something" # returns "something" 
False or "something" # returns "something" 
"" or "something" # returns "something" 

Si utiliza la variable de s para sostener algo que es o bien una referencia a la instancia de una clase o None (siempre que su clase no defina los miembros __nonzero__() y __len__()), es seguro usar la misma semántica que el operador de nulo coalescencia.

De hecho, incluso puede ser útil tener este efecto secundario de Python. Como sabe qué valores se evalúan como falsos, puede usar esto para activar el valor predeterminado sin usar None específicamente (un objeto de error, por ejemplo).

En algunos idiomas, este comportamiento se conoce como Elvis operator.

+3

¿Funcionará igual? Quiero decir, ¿se romperá si 's' es un valor válido pero no es verdad? (No sé Python, así que no estoy seguro de si el concepto de 'Truthy' se aplica.) – cHao

+6

El número 0, 'None', y los envases vacíos (incluyendo cadenas) son considerados falsos, además de la constante' Falso'. La mayoría de todo lo demás se considera verdad. Diría que el principal peligro aquí sería que obtendría un valor verdadero pero sin cadenas, pero eso no será un problema en algunos programas. – kindall

+15

El uso de este _otro obtendrá el valor predeterminado si s es Ninguno ** o Falso **, que puede no ser lo que se desea. – pafcu

38

estrictamente,

other = s if s is not None else "default value" 

lo contrario s = False se convertirá en "valor por defecto", que puede no ser lo que se pretendía.

Si usted quiere hacer este corto, trate

def notNone(s,d): 
    if s is None: 
     return d 
    else: 
     return s 

other = notNone(s, "default value") 
25

Aquí es una función que devuelve el primer argumento que no es ninguno:

def coalesce(*arg): 
    return reduce(lambda x, y: x if x is not None else y, arg) 

# Prints "banana" 
print coalesce(None, "banana", "phone", None) 

reducir() podría innecesariamente iterar sobre todo los argumentos incluso si el primer argumento no es Ninguno, por lo que también puede usar esta versión:

def coalesce(*arg): 
    for el in arg: 
    if el is not None: 
     return el 
    return None 
+14

'def coalescen (* arg): volver al lado ((a una de arg si a no hay ninguno), Ninguno) 'hace lo mismo que su último ejemplo en una línea. – glglgl

+1

Me da la circunstancia de que la gente quiere explicar si else sytnax, etc., pero coalesce toma una lista de argumentos arbitraria, así que esta debería ser la respuesta más importante. –

+2

glglgl tiene la mejor respuesta. Usé timeit en una matriz de prueba grande y la implementación de reducción es inaceptablemente lenta, la versión de múltiples líneas para/si es la más rápida, y la siguiente implementación queda muy rezagada. La próxima versión es la mejor en general al considerar la simplicidad y la concisión. – clay

1

En suma ition a la respuesta de Juliano sobre el comportamiento de "o": es "rápida"

>>> 1 or 5/0 
1 

Así que a veces es podría ser un atajo útil para cosas como

object = getCachedVersion() or getFromDB() 
+10

El término que está buscando es "cortocircuitos". – jpmc26

-3

Las dos funciones más adelante que he encontrado para ser muy útil cuando se trata de muchos casos de pruebas variables.

def nz(value, none_value, strict=True): 
    ''' This function is named after an old VBA function. It returns a default 
     value if the passed in value is None. If strict is False it will 
     treat an empty string as None as well. 

     example: 
     x = None 
     nz(x,"hello") 
     --> "hello" 
     nz(x,"") 
     --> "" 
     y = "" 
     nz(y,"hello") 
     --> "" 
     nz(y,"hello", False) 
     --> "hello" ''' 

    if value is None and strict: 
     return_val = none_value 
    elif strict and value is not None: 
     return_val = value 
    elif not strict and not is_not_null(value): 
     return_val = none_value 
    else: 
     return_val = value 
    return return_val 

def is_not_null(value): 
    ''' test for None and empty string ''' 
    return value is not None and len(str(value)) > 0 
+1

Este tipo de cosas añade un montón de poco diferente terminología (por ejemplo, "nulo" y "Nueva Zelanda" ninguno de los cuales significan nada en el contexto de Python), importado de otros idiomas, además de con las variantes (estrictas o no estrictas!) . Esto solo agrega confusión. Las comprobaciones explícitas "es ninguna" son lo que debería estar usando. Además, no obtiene el beneficio de ninguna semántica de corto alcance que los operadores puedan hacer cuando usa una llamada a función. – spookylukey

Cuestiones relacionadas