2011-02-01 8 views
8

Possible Duplicate:
How to programmatically set a global (module) variable?programmazione creazione di variabili in Python

ho una classe chiamata variabile definita come così:

class Variable(): 
    def __init__(self, name): 
     self.name = name 
     self._value = None 
    def value(self): 
     return self._value 
    def __repr__(self): 
     return self.name 

voglio creare istanze 26 capitali singola lettera di variabile in questo modo:

A = Variable('A') 
B = Variable('B') 
... 
Z = Variable('Z') 

Finora ho provato varie soluzioni, e il meglio che ho trovato è:

from string import uppercase 
for char in uppercase: 
    exec "%s = %s" % (char, Variable(str(char))) in None 

Tuttavia, questo non viene eseguito e mi dà questo errore:

Traceback (most recent call last): 
    File "C:\Users\Administrator\Dev\python\truthtable\truthtable.py", line 7, in <module> 
    exec "%s = %s" % (char, Variable(str(char))) in None 
    File "<string>", line 1, in <module> 
NameError: name 'A' is not defined 

Che cosa sto facendo di sbagliato?

+8

Oltre a cercare di creare variabili dinamicamente? –

+0

Er, il nome della domanda è un po 'traballante, non sono troppo concentrato su questo tipo di semantica. – deeb

+1

@deeb - Non penso che Ignacio si riferisse al tuo titolo. – senderle

risposta

15
from string import uppercase 
_g = globals() 
for char in uppercase: 
    _g[char] = Variable(char) 

Se questa è una buona idearimane discutibile :)

Questo funziona solo per globals() (cioè modulo assegnazioni di livello), come la definizione del linguaggio afferma esplicitamente che la modifica del dizionario restituito da locals() non possono in realtà cambia il valore di qualsiasi variabile locale.

È inoltre possibile eseguire operazioni simili con lo __dict__ di una classe o di un'istanza.

+0

La modifica di globals() non è una buona idea: non esiste alcuna garanzia ufficiale che funzioni: "Questo può fallire:" non c'è garanzia documentata che le modifiche a globals() in realtà permangano le modifiche al modulo sottostante. Funziona oggi, potrebbe rompersi domani. "(Alex Martelli) – EOL

+1

Questo non è corretto - questo avvertimento si applica * solo * ai locals(). Globals() è garantito che funzioni correttamente dalle specifiche del linguaggio. – ncoghlan

+0

@ncoghian: Ecco l'originale commento di Alex, che è probabilmente un programmatore Python molto esperto: http://stackoverflow.com/questions/1429814/how-to-programmatically-set-a-global-module-variable :) – EOL

0
from string import uppercase 
for c in uppercase: 
    locals()[c] = Variable(c) 
print A 

Non sono sicuro del motivo per cui si desidera farlo.

+2

Questo può fallire ufficialmente: "Il contenuto di questo dizionario non dovrebbe essere modificato, le modifiche potrebbero non influenzare i valori delle variabili locali e libere usate dall'interprete." (dalla documentazione). – EOL

4

Beh, non è abbastanza, ma è possibile accedere alla globals() dizionario direttamente:

for c in 'ABC': 
    globals()[c] = Variable(c) 
+1

"L'attribuzione attributo aggiorna il dizionario dello spazio dei nomi del modulo, ad es. M.x = 1 equivale a m .__ dict __ [" x "] = 1." (da http://docs.python.org/reference/datamodel.html) – ncoghlan

3

Non è necessario utilizzare exec per questo, come le altre risposte mostrano, ma qui è il problema con il vostro originale codice:

for char in uppercase: 
    exec "%s = %s" % (char, Variable(str(char))) in None 

Ciò exec A = A, B = B, ecc Mentre questo può essere interessante se sei un ardente seguace di oggettivismo, Python non si cura troppo per questo.

Volete avere la roba Variable() all'interno del exec per la sua importanza:

for char in uppercase: 
    exec "%s = Variable('%s')" % (char, char) 

In futuro, se si sta cercando di utilizzare exec, in primo luogo cercare di non farlo. In secondo luogo, stampa ciò che stai eseguendo - questo aiuterà a eseguire il debug.

+0

Nessun downvote, ma c'è un modo più pulito (e probabilmente più veloce, se questo è importante), come esplicitato nella mia risposta. – EOL

+0

Certo che c'è, dico di non farlo in questo modo nella mia risposta. Questa è una versione fissa del codice originale che usa effettivamente 'exec'. – tkerwin

7

L'approccio più pulito in assoluto che io abbia mai visto è quello di aggiungere direttamente le variabili (ad esempio gli attributi) al vostro programma (cioè modulo principale), come risposta in another question on StackOverflow:

import sys 
from string import ascii_uppercase 

this_module = sys.modules[__name__] 
for char in ascii_uppercase: 
    setattr(this_module, char, Variable(char)) 

print A # Works! 

PS: nucleo Python gli sviluppatori hanno lavorato sodo per rendere possibile la modifica di globals() (vedere i commenti alla risposta di ncoghlan). Quindi, la modifica di globals() è un'alternativa.Non sono sicuro del motivo per cui molte persone ritengono che non sia così pulito, anche se (forse perché il fatto che globals() può essere modificato non è esplicitamente documentato?).

2

Non tentare di inserirlo in una variabile globale. È orribile. Fallo invece.

import string 

variables = {} 
for x in string.ascii_uppercase: 
    variables[x] = Variable(x) 

La si accede da variables['Q'], per esempio.

Se si vuole attribuire l'accesso si può fare:

class Variables(object): pass 

e

variables = Variables() 
for x in string.ascii_uppercase: 
    setattr(variables, x) = Variable(x) 

Ma in questo caso preferisco creare dinamicamente in una classe di variabili container.

import string 

class Variable(object): 
    def __init__(self, value): 
     self.value = value 
    def __repr__(self): 
     return "<Variable %s>" % self.value 

class Variables(object): 
    def __getattr__(self, n): 
     if n in string.ascii_uppercase: 
      v = Variable(n) 
      setattr(self, n, v) 
      return v 
     raise AttributeError("Variables instance has no attribute %s" % n) 

Usage:

>>> v = Variables() 
>>> v.G 
<Variable G> 
>>> v.Y 
<Variable Y> 
>>> v.G is v.G 
True 

Semplice e pulito, nessun hack brutto (beh, tranne un getattr, e non è così brutto), e non hanno nemmeno bisogno di fare le variabili don ne ho bisogno

+0

Mentre sono d'accordo sul fatto che questo è di solito la strada da percorrere, ci sono sicuramente dei casi d'uso per aggiungere molti oggetti direttamente nello spazio dei nomi locale, ad es. per la matematica. x == sin (w) * (y + exp (-z)) è mondo migliore di v.x == m.sin (v.w) * (v.y + m.exp (-v.z)). – DSM

+0

Beh, penso che l'ossessione dei matematici con i nomi variabili di una lettera lungo sia un errore in primo luogo. :) È utile quando fai i tuoi calcoli su carta o semplifica/espandi le formule. Ma nella effettiva implementazione di una formula in un linguaggio di programmazione? Nyaaahhh sono scettico ... :-) –

+2

Forse puoi rimuovere immediatamente tutti i "v." e "m." nella mia seconda espressione e vedo la prima espressione, ma ho dovuto confrontarli quasi con carattere per carattere per essere sicuro che fossero uguali. Una lettera in più per ogni variabile e funzione, e un punto che mi fa pensare alla moltiplicazione. Ho molta più probabilità di perdere un errore evidente nella seconda forma, in quanto devo superare anni di esperienza nella lettura della forma standard senza che siano presenti personaggi estranei. La leggibilità conta, come ho sentito qualcuno dire da qualche parte ;-), e quel principio non sempre si inclina a favore di più personaggi. – DSM