2010-10-14 11 views
53

In caso contrario, qual è il modo migliore per farlo?Python ha una funzione "o uguale a" come || = in Ruby?

In questo momento mi sto facendo (per un progetto Django):

if not 'thing_for_purpose' in request.session: 
    request.session['thing_for_purpose'] = 5 

ma la sua piuttosto imbarazzante. In Ruby sarebbe:

request.session['thing_for_purpose'] ||= 5 

che è molto più bello.

+20

Si noti che questi due bit di codice sono in realtà molto diversi: la versione di Python lo imposta su 5 se non è nel Dict del tutto, dove la versione Ruby imposta anche a 5 se è impostata su qualsiasi valore falso. –

+1

@Glenn, non molto diverso, ma molto diverso. Poiché un valore hash non inizializzato restituisce 'nil' (falso nel contesto booleano) questo idioma è spesso usato esattamente per lo scopo che sean ha usato. L'idioma funziona solo se, ovviamente, 'nil' e' false' non sono valori legittimi nell'hash (che è molto spesso vero, quindi l'idioma va bene) – horseyguy

+7

@banister: non so dove si possa disegnare la linea tra "molto" e "abbastanza", ma il punto è che queste non sono affermazioni equivalenti, ed è importante capire la differenza. (False è molto spesso un valore valido in un hash, che ti morderà quando vuoi impostare un valore predefinito per un campo booleano su true, è una lacuna significativa dell'idioma di Ruby.) –

risposta

134

La risposta accettata è un bene per dicts, ma il titolo cerca un equivalente generale a || = operatore di Ruby. Un modo comune di fare qualcosa di simile || = in Python è

x = x or new_value 
+21

Questa risposta è probabile che cosa cercano le persone che vengono da una ricerca su Google. – gradi3nt

+0

Questa è davvero la migliore risposta. – AdamC

+3

Nota che a differenza di Ruby, questo codice funzionerà solo se 'x' è stato precedentemente definito (ad esempio impostato su' None' in un metodo di inizializzazione della classe). – olito

14

dict ha setdefault().

Quindi, se request.session è un dict:

request.session.setdefault('thing_for_purpose', 5) 
+0

Vagamente simile ma in nessun modo l'equivalente di Rubrica || =. – AdamC

+0

Per un dict funziona esattamente come Ruby || = –

+0

È significativamente diverso in quanto l'espressione predefinita viene valutata anche se la chiave è già impostata. Non esiste alcun modo per risolvere la domanda originale senza valutare il valore predefinito o accedere al tasto più di una volta o entrambi. – slinkp

9

impostazione di default ha un senso se si sta facendo in un middleware o qualcosa del genere, ma se avete bisogno di un valore predefinito nel contesto di una richiesta:

request.session.get('thing_for_purpose', 5) # gets a default 

bonus: ecco come fare veramente uno ||= in Python.

def test_function(self, d=None): 
    'a simple test function' 
    d = d or {} 

    # ... do things with d and return ... 
0

In generale, è possibile utilizzare dict[key] = dict.get(key, 0) + val.

2

risposta precisa: No. Python non ha un unico operatore integrato op che può tradursi in x = x or yx op y.

Ma quasi. L'operatore bitmap o uguale a (|=) funzionerà come come descritto sopra se entrambi gli operandi vengono trattati come booleani, con un avvertimento. (Qual è l'avvertenza risposta è inferiore ovviamente?).

In primo luogo, la dimostrazione di base della funzionalità:

x = True 
x  
Out[141]: True 

x |= True 
x  
Out[142]: True 

x |= False 
x  
Out[143]: True 

x &= False 
x  
Out[144]: False 

x &= True 
x  
Out[145]: False 

x |= False 
x  
Out[146]: False 

x |= True 
x 
Out[147]: True 

L'avvertimento è dovuto python non essere strettamente tipizzato e, quindi, anche se sono in corso i valori trattati come booleani in un'espressione non saranno cortocircuitati se dati ad un operatore bit a bit. Per esempio, supponiamo che abbiamo avuto una funzione booleana che cancella una lista e restituisce True se e solo se non ci sono stati elementi eliminati:

def my_clear_list(lst): 
    if not lst: 
     return False 
    else: 
     del lst[:] 
     return True 

Ora possiamo vedere il comportamento in cortocircuito come così:

x = True 
lst = [1, 2, 3] 
x = x or my_clear_list(lst) 
print(x, lst) 

Output: True [1, 2, 3] 

Tuttavia, la commutazione di or in un bit per bit o (|) rimuove il cortocircuito, quindi viene eseguita la funzione my_clear_list.

x = True 
lst = [1, 2, 3] 
x = x | my_clear_list(lst) 
print(x, lst) 

Output: True [] 

Sopra, x = x | my_clear_list(lst) è equivalente a x |= my_clear_list(lst).

Problemi correlati