¿Cómo creo un número variable de variables?

¿Cómo logro variables variables en Python?

Aquí hay una entrada manual elaborativa, por ejemplo: Variables variables

He oído que esto es una mala idea en general, y es un agujero de seguridad en Python. ¿Es eso cierto?

Puedes usar los diccionarios para lograr esto. Los diccionarios son almacenes de claves y valores.

>>> dct = {'x': 1, 'y': 2, 'z': 3} >>> dct {'y': 2, 'x': 1, 'z': 3} >>> dct["y"] 2 

Puede usar nombres de clave variable para lograr el efecto de variables variables sin el riesgo de seguridad.

 >>> x = "spam" >>> z = {x: "eggs"} >>> z["spam"] 'eggs' 

Para los casos en los que estás pensando en hacer algo como

 var1 = 'foo' var2 = 'bar' var3 = 'baz' ... 

una lista puede ser más apropiada que un dict. Una lista representa una secuencia ordenada de objetos, con índices enteros:

 l = ['foo', 'bar', 'baz'] print(l[1]) # prints bar, because indices start at 0 l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes'] 

Para las secuencias ordenadas, las listas son más convenientes que los dictados con claves enteras, porque las listas admiten la iteración en orden de índice, segmentación , append y otras operaciones que requerirían una gestión de claves incómoda con un dict.

Use la función incorporada getattr para obtener un atributo en un objeto por nombre. Modificar el nombre según sea necesario.

 obj.spam = 'eggs' name = 'spam' getattr(obj, name) # returns 'eggs' 

No es una buena idea. Si está accediendo a una variable global, puede usar globals() .

 >>> a = 10 >>> globals()['a'] 10 

Si desea acceder a una variable en el ámbito local, puede usar locals() , pero no puede asignar valores al dict devuelto.

Una mejor solución es usar getattr o almacenar sus variables en un diccionario y luego acceder a ellas por su nombre.

Siempre que quiera usar variables variables, probablemente sea mejor usar un diccionario. Así que en lugar de escribir

 $foo = "bar" $$foo = "baz" 

usted escribe

 mydict = {} foo = "bar" mydict[foo] = "baz" 

De esta manera, no sobrescribirá accidentalmente las variables existentes anteriormente (que es el aspecto de seguridad) y puede tener diferentes “espacios de nombres”.

Los nuevos codificadores a veces escriben código como este:

 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) ... 

Luego, el codificador se queda con una stack de variables con nombre, con un esfuerzo de encoding de O ( m * n ), donde m es el número de variables con nombre yn es el número de veces que se debe acceder a ese grupo de variables (incluida la creación ). El principiante más astuto observa que la única diferencia en cada una de esas líneas es un número que cambia según una regla, y decide utilizar un bucle. Sin embargo, se atascan en cómo crear dinámicamente esos nombres de variables y pueden intentar algo como esto:

 for i in range(10): my_calculator.('button_%d' % i) = tkinter.Button(root, text=i) 

Pronto descubren que esto no funciona.

Si el progtwig requiere una variable arbitraria de “nombres”, un diccionario es la mejor opción, como se explica en otras respuestas. Sin embargo, si simplemente está tratando de crear muchas variables y no le importa referirse a ellas con una secuencia de enteros, probablemente esté buscando una list . Esto es particularmente cierto si sus datos son homogéneos, como lecturas diarias de temperatura, puntajes semanales de cuestionarios o una cuadrícula de widgets gráficos.

Esto se puede montar de la siguiente manera:

 my_calculator.buttons = [] for i in range(10): my_calculator.buttons.append(tkinter.Button(root, text=i)) 

Esta list también se puede crear en una línea con una comprensión:

 my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)] 

El resultado en cualquier caso es una list poblada, con el primer elemento al que se accede con my_calculator.buttons[0] , el siguiente con my_calculator.buttons[1] , y así sucesivamente. El nombre de la variable “base” se convierte en el nombre de la list y el identificador variable se utiliza para acceder a ella.

Finalmente, no olvide otras estructuras de datos, como el set , esto es similar a un diccionario, excepto que cada “nombre” no tiene un valor adjunto. Si simplemente necesita una “bolsa” de objetos, esta puede ser una excelente opción. En lugar de algo como esto:

 keyword_1 = 'apple' keyword_2 = 'banana' if query == keyword_1 or query == keyword_2: print('Match.') 

Tendrás esto:

 keywords = {'apple', 'banana'} if query in keywords: print('Match.') 

Use una list para una secuencia de objetos similares, un set para una bolsa de objetos ordenada arbitrariamente o un dict para una bolsa de nombres con valores asociados.

En lugar de un diccionario, también puede utilizar nameduuple desde el módulo de colecciones, lo que facilita el acceso.

por ejemplo:

 #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 

Tienes que usar globals() construido en el método para lograr ese comportamiento:

 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 

Si no desea usar ningún objeto, aún puede usar setattr() dentro de su módulo actual:

 import sys current_module = module = sys.modules[__name__] # ie 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 

La clase SimpleNamespace podría usarse para crear nuevos atributos con setattr , o la subclase SimpleNamespace y crear su propia función para agregar nuevos nombres de atributos (variables).

 from types import SimpleNamespace variables = {"b":"B","c":"C"} a = SimpleNamespace(**v) setattr(a,"g","G") ag = "G+" something = aa 

Usar globals()

En realidad, puede asignar variables al scope global de forma dinámica, por ejemplo, si desea 10 variables a las que se puede acceder en un scope global i_1 , i_2i_10 :

 for i in range(10): globals()['i_{}'.format(i)] = 'a' 

Esto asignará ‘a’ a todas estas 10 variables, por supuesto, también puede cambiar el valor dinámicamente. Se puede acceder a todas estas variables ahora como a otra variable declarada globalmente:

 >>> i_5 'a' 

Estoy respondiendo la pregunta: ¿Cómo obtener el valor de una variable dado su nombre en una cadena? que está cerrado como un duplicado con un enlace a esta pregunta.

Si las variables en cuestión son parte de un objeto (parte de una clase, por ejemplo), entonces algunas funciones útiles para lograr exactamente eso son hasattr , getattr y setattr .

Así, por ejemplo, puedes tener:

 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) 

Entonces puedes hacer:

 v = Variables() v.get_var("foo") 

“initial_variable”

 v.create_new_var(v.foo,"is actually not initial") v.initial_variable 

“en realidad no es inicial”

El consenso es utilizar un diccionario para esto, ver las otras respuestas. Esta es una buena idea para la mayoría de los casos, sin embargo, hay muchos aspectos que surgen de esto:

  • Usted mismo será responsable de este diccionario, incluida la recolección de basura (de variables in-dict), etc.
  • no hay localidad o globalidad para variables variables, depende de la globalidad del diccionario
  • Si desea cambiar el nombre de una variable, deberá hacerlo manualmente.
  • Sin embargo, usted es mucho más flexible, por ejemplo,
    • Puedes decidir sobrescribir las variables existentes o …
    • … elegir implementar variables const.
    • para hacer una excepción en la sobrescritura para diferentes tipos
    • etc.

Dicho esto, he implementado una variable de administrador de variables que proporciona algunas de las ideas anteriores. Funciona para python 2 y 3.

Usarías la clase así:

 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']) 

Si desea permitir la sobrescritura de variables con el mismo tipo solamente:

 myVars = VariableVariablesManager(enforceSameTypeOnOverride = True) myVars['test'] = 25 myVars['test'] = "Cat" # <- raises Exception (different type on overwriting) 

Existe un método conocido para emular un contenedor para variables, que admite ambos métodos de acceso: mediante el nombre de una variable y una clave de cadena.

 class Vars: def __init__(self, **kw): self.__dict__.update(kw) def __getitem__(self, key): return self.__dict__[key] def __setitem__(self, key, val): self.__dict__[key] = val def __contains__(self, name): return name in self.__dict__ def __nonzero__(self): return bool(self.__dict__) def __iter__(self): return iter(self.__dict__) def __len__(self): return len(self.__dict__) def __copy__(self): return self.__class__(**self.__dict__) def __repr__(self): return 'Vars(' + ', '.join('%s=%r' % (k,v) for k,v in self.__dict__.items()) + ')' >>> vars = Vars() >>> vars.a = 1 >>> vars['b'] = 2 >>> print(vars) Vars(a=1, b=2) >>> print(vars['a'], vars.b) 1 2 >>> print(tuple(vars)) ('a', 'b') 

Cualquier conjunto de variables también se puede envolver en una clase. Las variables “variables” se pueden agregar a la instancia de la clase durante el tiempo de ejecución accediendo directamente al diccionario incorporado a través del atributo __dict__.

El siguiente código define la clase Variables, que agrega variables (en este caso atributos) a su instancia durante la construcción. Los nombres de las variables se toman de una lista específica (que, por ejemplo, podría haber sido generada por el código del progtwig):

 # 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(va, vb, vc) #will produce 100 100 100 

Consulte el siguiente ejemplo para crear variables en tiempo de ejecución. Puedes usar globals() .

 for i in range(3): globals() ['variable_'+str(i)] = i 

En el ejemplo anterior, quiero crear tres variables: variable_0 , variable_1 y variable_2 en tiempo de ejecución con valores 0,1 y 2 respectivamente.

 variable_0 [Output]:0 variable_1 [Output]:1 variable_2 [Output]:2 

Para acceder al valor de las variables creadas en el tiempo de ejecución, puede usar el método eval() siguiente manera:

 for i in range(3): globals() ['variable_'+str(i)] = i print('Variable Value:',eval('variable_'+str(i))) [Output]: Variable Value: 0 Variable Value: 1 Variable Value: 2 

puede utilizar la función incorporada vars()

 >>> foo = 'bar' >>> vars()[foo] = 'something' >>> bar 'something'