Come realizzo variabili variabili in Python?
Ecco una voce manuale elaborativa, ad esempio: Variabili variabili
Ho sentito che questa è una cattiva idea in generale, ed è una falla nella sicurezza di Python. È vero?
Come realizzo variabili variabili in Python?
Ecco una voce manuale elaborativa, ad esempio: Variabili variabili
Ho sentito che questa è una cattiva idea in generale, ed è una falla nella sicurezza di Python. È vero?
Risposte:
È possibile utilizzare i dizionari per ottenere questo risultato. I dizionari sono archivi di chiavi e valori.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2
È possibile utilizzare i nomi delle chiavi delle variabili per ottenere l'effetto delle variabili senza il rischio per la sicurezza.
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
Per i casi in cui stai pensando di fare qualcosa del genere
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
un elenco può essere più appropriato di un dict. Un elenco rappresenta una sequenza ordinata di oggetti, con indici interi:
lst = ['foo', 'bar', 'baz']
print(lst[1]) # prints bar, because indices start at 0
lst.append('potatoes') # lst is now ['foo', 'bar', 'baz', 'potatoes']
Per le sequenze ordinate, elenchi sono più convenienti di dicts con chiavi intere, perché le liste iterazione supportano in ordine di indice, affettare , append
e altre operazioni che richiederebbero gestione delle chiavi imbarazzante con un dict.
Utilizzare la getattr
funzione integrata per ottenere un attributo su un oggetto per nome. Modifica il nome secondo necessità.
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
Non è una buona idea. Se si accede a una variabile globale è possibile utilizzare globals()
.
>>> a = 10
>>> globals()['a']
10
Se si desidera accedere a una variabile nell'ambito locale è possibile utilizzare locals()
, ma non è possibile assegnare valori al dict restituito.
Una soluzione migliore è utilizzare getattr
o archiviare le variabili in un dizionario e quindi accedervi per nome.
x = "foo"
e locals()["x"] = "bar"
utilizzato print x
fornisce l'output bar
per Jython 2.5.2. Questo è stato testato con uno script di automazione su richiesta in maximo .
Ogni volta che vuoi usare variabili variabili, probabilmente è meglio usare un dizionario. Quindi invece di scrivere
$foo = "bar"
$$foo = "baz"
Scrivi
mydict = {}
foo = "bar"
mydict[foo] = "baz"
In questo modo non si sovrascriveranno accidentalmente variabili precedentemente esistenti (che è l'aspetto della sicurezza) e si possono avere diversi "spazi dei nomi".
I nuovi programmatori a volte scrivono codice in questo modo:
my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...
Il codificatore viene quindi lasciato con una pila di variabili denominate, con uno sforzo di codifica di O ( m * n ), dove m è il numero di variabili nominate e n è il numero di volte in cui è necessario accedere al gruppo di variabili (inclusa la creazione ). Il principiante più astuto osserva che l'unica differenza in ciascuna di quelle righe è un numero che cambia in base a una regola e decide di utilizzare un ciclo. Tuttavia, rimangono bloccati su come creare dinamicamente quei nomi di variabili e possono provare qualcosa del genere:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Presto scoprono che questo non funziona.
Se il programma richiede "nomi" variabili arbitrari, un dizionario è la scelta migliore, come spiegato in altre risposte. Tuttavia, se stai semplicemente cercando di creare molte variabili e non ti dispiace fare riferimento a esse con una sequenza di numeri interi, probabilmente stai cercando unlist
. Ciò è particolarmente vero se i tuoi dati sono omogenei, come letture della temperatura giornaliera, punteggi settimanali dei quiz o una griglia di widget grafici.
Questo può essere assemblato come segue:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Questo list
può anche essere creato in una riga con una comprensione:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Il risultato in entrambi i casi è popolato list
, con l'accesso al primo elemento my_calculator.buttons[0]
, il successivo con my_calculator.buttons[1]
e così via. Il nome della variabile "base" diventa il nome del filelist
e l'identificatore variabile viene utilizzato per accedervi.
Infine, non dimenticare altre strutture di dati, come il set
- questo è simile a un dizionario, tranne per il fatto che ogni "nome" non ha un valore associato. Se hai semplicemente bisogno di una "borsa" di oggetti, questa può essere un'ottima scelta. Invece di qualcosa del genere:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
Avrai questo:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Utilizzare a list
per una sequenza di oggetti simili, a set
per un sacchetto di oggetti ordinato in modo arbitrario o a dict
per un sacchetto di nomi con valori associati.
Invece di un dizionario puoi anche usare namedtuple
dal modulo collezioni, che semplifica l'accesso.
Per esempio:
# using dictionary
variables = {}
variables["first"] = 34
variables["second"] = 45
print(variables["first"], variables["second"])
# using namedtuple
Variables = namedtuple('Variables', ['first', 'second'])
vars = Variables(34, 45)
print(vars.first, vars.second)
Se non si desidera utilizzare alcun oggetto, è comunque possibile utilizzare setattr()
all'interno del modulo corrente:
import sys
current_module = module = sys.modules[__name__] # i.e the "file" where your code is written
setattr(current_module, 'variable_name', 15) # 15 is the value you assign to the var
print(variable_name) # >>> 15, created from a string
__dict__
Tuttavia, questo non funziona con le variabili. Mi chiedo se esiste un meccanismo generale per creare dinamicamente qualsiasi variabile globale.
globals()
posso farlo
La SimpleNamespace
classe può essere utilizzata per creare nuovi attributi con setattr
o sottoclasse SimpleNamespace
e creare la propria funzione per aggiungere nuovi nomi di attributi (variabili).
from types import SimpleNamespace
variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
Sto rispondendo alla domanda: come ottenere il valore di una variabile dato il suo nome in una stringa? che è chiuso come duplicato con un link a questa domanda.
Se le variabili in questione sono parte di un oggetto (parte di una classe ad esempio), allora alcune funzioni utili per ottenere esattamente che sono hasattr
, getattr
esetattr
.
Quindi ad esempio puoi avere:
class Variables(object):
def __init__(self):
self.foo = "initial_variable"
def create_new_var(self,name,value):
setattr(self,name,value)
def get_var(self,name):
if hasattr(self,name):
return getattr(self,name)
else:
raise("Class does not have a variable named: "+name)
Quindi puoi fare:
v = Variables()
v.get_var("foo")
"Initial_variable"
v.create_new_var(v.foo,"is actually not initial")
v.initial_variable
"in realtà non è iniziale"
Uso globals()
Puoi effettivamente assegnare variabili all'ambito globale in modo dinamico, ad esempio, se vuoi 10 variabili a cui è possibile accedere su un ambito globale i_1
, i_2
... i_10
:
for i in range(10):
globals()['i_{}'.format(i)] = 'a'
Questo assegnerà 'a' a tutte queste 10 variabili, ovviamente puoi anche cambiare il valore in modo dinamico. È ora possibile accedere a tutte queste variabili come altre variabili dichiarate a livello globale:
>>> i_5
'a'
Devi usare il globals()
metodo integrato per ottenere quel comportamento:
def var_of_var(k, v):
globals()[k] = v
print variable_name # NameError: name 'variable_name' is not defined
some_name = 'variable_name'
globals()[some_name] = 123
print variable_name # 123
some_name = 'variable_name2'
var_of_var(some_name, 456)
print variable_name2 # 456
Il consenso è usare un dizionario per questo - vedi le altre risposte. Questa è una buona idea per la maggior parte dei casi, tuttavia ci sono molti aspetti che ne derivano:
Detto questo, ho implementato una classe di variabili variabili che fornisce alcune delle idee sopra. Funziona con Python 2 e 3.
Utilizzeresti la classe in questo modo:
from variableVariablesManager import VariableVariablesManager
myVars = VariableVariablesManager()
myVars['test'] = 25
print(myVars['test'])
# define a const variable
myVars.defineConstVariable('myconst', 13)
try:
myVars['myconst'] = 14 # <- this raises an error, since 'myconst' must not be changed
print("not allowed")
except AttributeError as e:
pass
# rename a variable
myVars.renameVariable('myconst', 'myconstOther')
# preserve locality
def testLocalVar():
myVars = VariableVariablesManager()
myVars['test'] = 13
print("inside function myVars['test']:", myVars['test'])
testLocalVar()
print("outside function myVars['test']:", myVars['test'])
# define a global variable
myVars.defineGlobalVariable('globalVar', 12)
def testGlobalVar():
myVars = VariableVariablesManager()
print("inside function myVars['globalVar']:", myVars['globalVar'])
myVars['globalVar'] = 13
print("inside function myVars['globalVar'] (having been changed):", myVars['globalVar'])
testGlobalVar()
print("outside function myVars['globalVar']:", myVars['globalVar'])
Se si desidera consentire la sovrascrittura delle variabili solo con lo stesso tipo:
myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
Ho provato entrambi in Python 3.7.3, puoi usare globals () o vars ()
>>> food #Error
>>> milkshake #Error
>>> food="bread"
>>> drink="milkshake"
>>> globals()[food] = "strawberry flavor"
>>> vars()[drink] = "chocolate flavor"
>>> bread
'strawberry flavor'
>>> milkshake
'chocolate flavor'
>>> globals()[drink]
'chocolate flavor'
>>> vars()[food]
'strawberry flavor'
Qualsiasi set di variabili può anche essere racchiuso in una classe. Le variabili "variabili" possono essere aggiunte all'istanza della classe durante il runtime accedendo direttamente al dizionario incorporato tramite l'attributo __dict__.
Il codice seguente definisce la classe Variables, che aggiunge variabili (in questo caso attributi) alla sua istanza durante la costruzione. I nomi delle variabili sono presi da un elenco specificato (che, ad esempio, avrebbe potuto essere generato dal codice del programma):
# some list of variable names
L = ['a', 'b', 'c']
class Variables:
def __init__(self, L):
for item in L:
self.__dict__[item] = 100
v = Variables(L)
print(v.a, v.b, v.c)
#will produce 100 100 100