2011-09-07 18 views
27

Sono un programmatore RoR nuovo in Python. Sto cercando di trovare la sintassi che mi consentirà di impostare una variabile su un valore specifico solo se non è stata assegnata in precedenza. Fondamentalmente voglio:Python: Assegna valore se non esiste nessuno

# only if var1 has not been previously assigned

var1 = 4

+6

In quale circostanza si farebbe riferimento a variabili che potrebbero non esistere? Vuoi fare riferimento a variabili che sono state dichiarate ma non ancora inizializzate? – mwcz

risposta

18

Questo è uno stile molto diverso di programmazione, ma cerco sempre di riscrivere le cose che sembravano

bar = None 
if foo(): 
    bar = "Baz" 

if bar is None: 
    bar = "Quux" 

in proprio:

if foo(): 
    bar = "Baz" 
else: 
    bar = "Quux" 

Vale a dire, provo difficile da evitare una situazione in cui alcuni percorsi di codice definiscono variabili ma altre no. Nel mio codice, non esiste mai un percorso che causi un'ambiguità dell'insieme di variabili definite (in realtà, di solito faccio un ulteriore passo avanti e mi assicuro che i tipi siano gli stessi indipendentemente dal percorso del codice). Potrebbe essere solo una questione di gusti personali, ma trovo questo schema, anche se un po 'meno ovvio quando lo sto scrivendo, molto più facile da capire quando lo leggerò più tardi.

+37

Questo potrebbe anche essere abbreviato in un one-liner utilizzando 'bar = "Baz" se foo() else "Quux"' – MatToufoutu

+0

@grokpot: che non dovrebbe cambiare nulla, entrambi i frammenti di codice deve essere assunto o meno per le stesse cose restituito da 'foo()' – SingleNegationElimination

+0

@grokpot: leggi attentamente i due snippet, non sta testando se 'foo()' ha restituito 'None', sta verificando se' bar' è ancora 'None'. Se puoi fornire una definizione di 'foo()' che farà sì che i due frammenti diano assegnazioni differenti 'bar', ti comprerò una bottiglia di fantasia di Scotch (o qualsiasi altra cosa tu preferisca) – SingleNegationElimination

56

Si dovrebbe inizializzare le variabili a nessuno e quindi controllare che:

var1 = None 
if var1 is None: 
    var1 = 4 

che può essere scritta in una linea come:

var1 = 4 if var1 is None else var1 

o usando la scorciatoia (ma controllando Si raccomanda None)

var1 = var1 or 4 

in alternativa, se non si ha nulla assegnato alla variabile che il nome variabile non esiste e quindi usando che più tardi alzerà NameError, ed è anche possibile utilizzare queste conoscenze per fare qualcosa di simile

try: 
    var1 
except NameError: 
    var1 = 4 

ma vorrei sconsigliarlo.

+0

Si noti che se si desidera assegnare un valore, è necessaria una dichiarazione 'global' /' nonlocal' o si utilizza 'except UnboundLocalError' (e si accetta che la variabile sia locale e un valore impostato a livello globale venga ignorato). – delnan

+0

@delnan dove nel mio esempio otterrei UnboundLocalError? –

+2

A causa del compito in seguito (in 'except'),' var1' è una variabile locale a meno che lo snippet sia a livello di modulo (cioè globale) o ci sia una riga 'globale var1'. L'accesso a una variabile locale non ancora assegnata solleva 'UnboundLocalError' invece di' NameError' (che è riservato ai nomi globali). – delnan

0

Se vuoi dire una variabile a livello di modulo, allora si può usare "globali":

if "var1" not in globals(): 
    var1 = 4 

ma il linguaggio Python comune è quello di inizializzare dire None (ammesso che non è un valore accettabile) e quindi testare con if var1 is not None.

+7

In questo modo giace la follia. Questo rompe le variabili locali, usando interruzioni di 'locals()' su globali, e non penso che funzioni con nonlocali. Per risolvere ciò, si dovrebbero emulare le regole dell'intero scope o scrivere il codice assumendo uno di entrambi. – delnan

+2

@delnan: Informazioni su locale/non globale questo è ciò che intendevo con "Se si intende una variabile a livello di modulo". A proposito di quell'idiota "In questo modo giace la follia" dovresti dire all'OP, non a me ... comunque nella risposta viene effettivamente detto che non è così che dovrebbero essere fatte le cose. – 6502

15
var1 = var1 or 4 

L'unico problema che questo potrebbe avere è che se var1 è un valore Falsey, come False o 0 o [], che sceglierà 4 invece. Questo potrebbe essere un problema.

+2

Vedere [test del valore di verità] (https://docs.python.org/2/library/stdtypes.html#truth-value-testing) per un elenco completo di elementi che valutano su False, alcuni di essi potrebbero sorprendere per alcuni . – ecerulm

2

La risposta di IfLoop (e il commento di MatToufoutu) funzionano perfettamente per variabili indipendenti, ma volevo fornire una risposta a chiunque cerchi di fare qualcosa di simile per le singole voci in liste, tuple o dizionari.

Dizionari

existing_dict = {"spam": 1, "eggs": 2} 
existing_dict["foo"] = existing_dict["foo"] if "foo" in existing_dict else 3 

Returns {"spam": 1, "eggs": 2, "foo": 3}

Liste

existing_list = ["spam","eggs"] 
existing_list = existing_list if len(existing_list)==3 else 
       existing_list + ["foo"] 

Returns ["spam", "eggs", "foo"]

tuple

existing_tuple = ("spam","eggs") 
existing_tuple = existing_tuple if len(existing_tuple)==3 else 
       existing_tuple + ("foo",) 

Returns ("spam", "eggs", "foo")

(Non dimenticare la virgola in ("foo",) per definire una tupla "single".)

La soluzione liste e tuple sarà più complicato se si vuole fare di più che controllare la lunghezza e aggiungere alla fine. Tuttavia, questo dà un sapore di ciò che puoi fare.

+0

Tutte le tue risposte sono rotte. –

+1

@ SébastienDeprez Eri davvero corretto. Grazie per la segnalazione. Da allora ho apportato delle modifiche per risolvere i problemi. –

10

Anche io vengo da Ruby quindi adoro la sintassi foo ||= 7.

Questa è la cosa più vicina che riesco a trovare.

foo = foo if 'foo' in vars() else 7 

persone che ho visto fare questo per un dict:

try: 
    foo['bar'] 
except KeyError: 
    foo['bar'] = 7 

Upadate: Tuttavia, di recente ho trovato questo gioiello:

foo['bar'] = foo.get('bar', 7) 

Se ti piace quello, quindi per una variabile regolare puoi fare qualcosa del genere:

vars()['foo'] = vars().get('foo', 7) 
+0

Come funzionerebbe, ad esempio, le variabili in una classe? self.foo = ...? – CodeKid

+1

@CodeKid self.foo = self .__ dict __ '. Get ('foo', 7)' –

+1

@CodeKid Oppure, 'self.foo = getattr (self, 'pippo', 7)' – kkurian

Problemi correlati