C'è un equivalente pitone dell'operatore c # null-coalescente?
-
12-11-2019 - |
Domanda
in c # c'è un operatore null-coalescing (scritto come ??
) che consente una facile (corta) controllo nullo durante l'assegnazione:
string s = null;
var other = s ?? "some default value";
.
C'è un equivalente Python?
So che posso fare:
s = None
other = s if s else "some default value"
.
Ma c'è un modo ancora più breve (dove non ho bisogno di ripetere s
)?
Soluzione
other = s or "some default value"
.
OK, deve essere chiarito come funziona l'operatore or
. È un operatore booleano, quindi funziona in un contesto booleano. Se i valori non sono booleani, vengono convertiti in boolean ai fini dell'operatore.
Si noti che l'operatore or
non restituisce solo True
o False
TagCode. Invece, restituisce il primo operando se il primo operando valuta il vero, e restituisce il secondo operando se il primo operando valuta false.
In questo caso, l'espressione x or y
restituisce x
se è True
o valuta il vero quando convertito in booleano. Altrimenti, restituisce y
. Per la maggior parte dei casi, questo servirà per lo stesso scopo dell'operatore null-coalescente di C♯, ma tieni presente:
42 or "something" # returns 42
0 or "something" # returns "something"
None or "something" # returns "something"
False or "something" # returns "something"
"" or "something" # returns "something"
.
Se si utilizza la variabile s
per tenere utile qualcosa che è un riferimento all'istanza di una classe o None
(a condizione che la classe non definisca i membri __nonzero__()
e __len__()
), è sicuro utilizzare la stessa semantica del Operatore NULL-Coalescing.
In effetti, potrebbe anche essere utile avere questo effetto collaterale di Python. Dal momento che sai quali valori valutano il falso, è possibile utilizzarlo per attivare il valore predefinito senza utilizzare None
specificamente (un oggetto di errore, ad esempio).
In alcune lingue questo comportamento è indicato come Elvis operator .
Altri suggerimenti
rigorosamente,
other = s if s is not None else "default value"
.
In caso contrario, s = False
diventerà "default value"
, che potrebbe non essere quello che è stato inteso.
Se vuoi renderlo più breve, prova:
def notNone(s,d):
if s is None:
return d
else:
return s
other = notNone(s, "default value")
. Ecco una funzione che restituirà il primo argomento che non è None
:
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)
.
reduce()
potrebbe inutilmente iterare su tutti gli argomenti anche se il primo argomento non è None
, in modo da poter utilizzare anche questa versione:
def coalesce(*arg):
for el in arg:
if el is not None:
return el
return None
. Mi rendo conto che questo è una risposta, ma c'è un'altra opzione quando hai a che fare con gli oggetti.
Se hai un oggetto che potrebbe essere:
{
name: {
first: "John",
last: "Doe"
}
}
.
Puoi usare:
obj.get(property_name, value_if_null)
.
Come:
obj.get("name", {}).get("first", "Name is missing")
.
Aggiungendo {}
come valore predefinito, se manca il "nome", un oggetto vuoto viene restituito e passato fino al prossimo GET.Questo è simile a NULL-Safe-Navigation in C #, che sarebbe come obj?.name?.first
.
Oltre alla risposta di Juliano sul comportamento di "o": È "veloce"
>>> 1 or 5/0
1
.
Quindi a volte è potrebbe essere un utile collegamento per cose come
object = getCachedVersion() or getFromDB()
. Per quanto riguarda le risposte di @hugh Bothwell, @.Rortehu e @glglGL.
Setup set di dati per il test
import random
dataset = [random.randint(0,15) if random.random() > .6 else None for i in range(1000)]
.
Definisci implementazioni
def not_none(x, y=None):
if x is None:
return y
return x
def coalesce1(*arg):
return reduce(lambda x, y: x if x is not None else y, arg)
def coalesce2(*args):
return next((i for i in args if i is not None), None)
.
FARE FUNZIONE TEST
def test_func(dataset, func):
default = 1
for i in dataset:
func(i, default)
.
Risultati su Mac I7 @ 2.7GHz usando Python 2.7
>>> %timeit test_func(dataset, not_none)
1000 loops, best of 3: 224 µs per loop
>>> %timeit test_func(dataset, coalesce1)
1000 loops, best of 3: 471 µs per loop
>>> %timeit test_func(dataset, coalesce2)
1000 loops, best of 3: 782 µs per loop
.
Chiaramente la funzione not_none
risponde correttamente alla domanda dell'OP e gestisce il problema "falsy". È anche il più veloce e più facile da leggere. Se applicazione della logica in molti luoghi, è chiaramente il modo migliore per andare.
Se hai un problema in cui vuoi trovare il 1 ° valore non nullo in un Iterable, allora @ la risposta di Mortehu è la strada da percorrere. Ma è una soluzione a diverso problema che op, sebbene possa gestire parzialmente quel caso. Non può richiedere un valore Iterable e un valore predefinito. L'ultimo argomento sarebbe il valore predefinito restituito, ma non passeresti in unicabile in tal caso così come non è esplicito che l'ultimo argomento sia un valore predefinito da valutare.
Si potrebbe quindi fare sotto, ma userei ancora not_null
per il caso di utilizzo a valore singolo.
.def coalesce(*args, **kwargs):
default = kwargs.get('default')
return next((a for a in arg if a is not None), default)
Python has a get function that its very useful to return a value of an existent key, if the key exist;
if not it will return a default value.
def main():
names = ['Jack','Maria','Betsy','James','Jack']
names_repeated = dict()
default_value = 0
for find_name in names:
names_repeated[find_name] = names_repeated.get(find_name, default_value) + 1
.
Se non riesci a trovare il nome all'interno del dizionario, restituirà il default_value, Se il nome esiste, aggiungerà qualsiasi valore esistente con 1.
Spero che questo possa aiutare
Le due funzioni di seguito ho trovato molto utile quando si tratta di molti casi di test variabili.
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
.