2012-07-20 12 views
5

mi sono imbattuto in un'espressione interessante in Ruby:C'è qualche espressione in python che simile al rubino del || =

a ||= "new" 

Ciò significa che se una non è definito, il valore "nuovo" sarà assegnato a un; altrimenti, a sarà lo stesso com'è. È utile quando si esegue una query DB. Se il valore è impostato, non desidero attivare un'altra query DB.

così ho provato la mentalità simile in Python:

a = a if a is not None else "new" 

E 'fallito. Lo penso perché non puoi fare "a = a" in Python, se a non è definito.

Quindi le soluzioni che posso venire fuori stanno controllando i locali() e globali(), o utilizzando provare ... ad eccezione di espressione:

myVar = myVar if 'myVar' in locals() and 'myVar' in globals() else "new" 

o

try: 
    myVar 
except NameError: 
    myVar = None 

myVar = myVar if myVar else "new" 

Come possiamo vedere , le soluzioni non sono così eleganti. Quindi mi piacerebbe chiedere, c'è un modo migliore per farlo?

+0

nota che l'uso usuale di 'variabile || = valore' è quello di impostare un valore predefinito su una variabile già definita, utilizzandolo per definire variabili che possono o non possono esistere sono scarse pratiche IMHO. – tokland

+1

La soluzione try-except è, credo, la più Pythonic. Certo, non è così conciso come un singolo operatore, ma è chiaro e leggibile. –

+0

'myVar = myVar se myVar else" new "' - sii consapevole che questo è python e non ruby, e molte cose sono considerate false in un contesto booleano –

risposta

3

ne dite?

try: 
    a = a 
except NameError: 
    a = "new" 

Non è molto breve ma chiaramente (almeno per me) spiega l'intento del codice.

+0

Non è lo stesso codice mostrato nella domanda? –

+1

Non proprio. Nella domanda, a è impostato su Nessuno, quindi viene utilizzata un'espressione ternaria per impostare un "nuovo". E l'espressione ternaria come scritta fallirà se a è [] o qualsiasi altra cosa che valuti False. Come accennato in precedenza, è necessario fare "a is not None". – casevh

+0

Hai ragione, ho letto la domanda sbagliata, da qui il mio commento, dove dico che quella parte è una buona soluzione :) –

5

L'utilizzo di una variabile non definita come "predefinito" è un po 'di odore di codice. Come hai scoperto, fallisce perché non puoi fare a = a se non esiste già. È meglio inizializzare la variabile con un valore predefinito (come None) e quindi controllarla. Quindi hai praticamente trovato la soluzione. L'unica cosa è che invece di lasciare la tua variabile non finalizzata e provare a usare "does not exist" come valore "mancante", devi inizializzarla esplicitamente. Così, invece di fare questo:

# code with no initialization. . . 
a ||= blah 

fare questo:

a = None 
# code 
if a is None: 
    a = blah 
+0

Il vantaggio di 'a || = blah' è che non è necessario preparare il valore in anticipo ed è semplice e breve. È abbastanza pulito. Ma immagino tu abbia ragione. Questo è il modo più semplice per farlo in Python. – Conan

+0

Potresti accorciare le ultime righe a: 'a = a se a non è nessun altro blah', o se sai che' a' sarà veritiera 'a = a o blah'. –

1

Se si voleva davvero questo comportamento si sarebbe migliore fuori in Python utilizzando un dict, ad esempio: d.get('a', 'new'). Il che significa che puoi masticare con globals()/locals(). get('a', 'new'), ma generalmente non è il modo di fare cose in Python - ogni associazione di nomi dovrebbe avere un valore iniziale anche se si tratta di una sorta di valore sentinella (come None).

orribile esempio con globali() e utilizzando setDefault()

>>> a 
Traceback (most recent call last): 
    File "<pyshell#66>", line 1, in <module> 
    a 
NameError: name 'a' is not defined 
>>> globals().setdefault('a', 'new') 
'new' 
>>> a 
'new' 
>>> a = 'old' 
>>> globals().setdefault('a', 'new') 
'old' 
>>> a 
'old' 
+0

concesso, è un ipotetico, ma probabilmente 'd.setdefault ('a', 'new')' sarebbe una scelta migliore. –

+0

Penso che get() non possa funzionare con globals() e locals(). Dopo averlo fatto, a non è ancora definito. – Conan

+0

@conan anche l'orribile esempio che ho aggiunto sembra funzionare (testato solo con la digitazione in, comunque in IDLE) –

1

Pythonic è che dovresti saperlo prima di usarlo specialmente in vars locali/globali piuttosto che indovinare dove si trova. È possibile scrivere questo codice, ma non è divinatorio

a = None 
# other codes 
a = a or 'new' 

va bene

1

considerare l'utilizzo di Memoizzazione, che è abbastanza Pythonic.Ecco un po 'di codice Python 2:

# Backport of Python 3's lru_cache 
# pip install functools32 
from functools32 import lru_cache 

@lru_cache() 
def expensive_db_query(arg): 
    print "Running expensive db query for", arg 
    return arg[::-1] 

expensive_db_query("spam") # prints "Running expensive db query for spam" 
expensive_db_query("spam") # No output 
expensive_db_query("eggs") # prints "Running expensive db query for eggs" 

Se si vuole avere la cache dimenticare valori dopo il tempo è trascorso e interrogare nuovamente il database, controlla Ilialuk's lru cache.

0

Ecco una variante ispirato this answer su come verificare se è definita una variabile:

a = a if "a" in vars() or "a" in globals() else "new" 

Non è così breve ma è almeno una linea.

In [1]: a 
--------------------------------------------------------------------------- 
NameError         Traceback (most recent call last) 
<ipython-input-1-60b725f10c9c> in <module>() 
----> 1 a 

NameError: name 'a' is not defined 

In [2]: a = a if "a" in vars() or "a" in globals() else "new" 

In [3]: a 
Out[3]: 'new' 

In [4]: a = "A exists!" 

In [5]: a = a if "a" in vars() or "a" in globals() else "new" 

In [6]: a 
Out[6]: 'A exists!' 

Detto questo, sono d'accordo con BrenBarn che si dovrebbe evitare il problema con una variabile non definita semplicemente dichiarandolo con a=None prima del blocco in cui non si potrebbe impostare.

Problemi correlati