2011-02-01 8 views
8

Possible Duplicate:
How to programmatically set a global (module) variable?mediante programación la creación de variables en Python

tengo una clase llamada variable definida como así:

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

Quiero crear instancias 26 de capital de una sola letra de la variable de la siguiente manera:

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

Hasta ahora he probado varias soluciones, y lo mejor que he encontrado es:

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

Sin embargo, esto no funciona y me da este error:

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 

¿Qué estoy haciendo mal?

+8

¿Aparte de tratar de crear variables dinámicamente? –

+0

Er, el nombre de la pregunta es un poco inseguro, no estoy muy al tanto de este tipo de semántica. – deeb

+1

@deeb - No creo que Ignacio se estuviera refiriendo a su título. – senderle

Respuesta

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

Si esto es una buena ideasigue siendo cuestionable :)

Esto sólo funciona para globals() (es decir, asignaciones de nivel de módulo), como la definición del lenguaje afirma explícitamente que la modificación del diccionario devuelto por locals() no puede realmente cambia el valor de cualquier variable local.

También puede hacer algo similar con el __dict__ de una clase o instancia.

+0

La modificación de globales() no es una buena idea: no existe una garantía oficial de que esto funcione: "Esto puede fallar:" no hay garantía documentada de que los cambios en globales() realmente persistan los cambios en el módulo subyacente. Funciona hoy, podría romperse mañana. "(Alex Martelli) – EOL

+1

Eso no es correcto - esa advertencia se aplica * solo * a los locales(). Globals() está garantizado que funciona correctamente según la especificación del idioma – ncoghlan

+0

@ncoghian: Aquí está el original un comentario de Alex, quien es posiblemente un programador de Python muy experimentado: 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 

No estoy seguro de por qué quieres hacer esto, sin embargo.

+2

Esto puede fallar oficialmente: "El contenido de este diccionario no debe modificarse; los cambios pueden no afectar los valores de las variables locales y gratuitas utilizadas por el intérprete". (de la documentación). – EOL

4

Bueno, no es bastante, pero se puede acceder al diccionario globals() directamente:

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

"La asignación de atributos actualiza el diccionario de espacios de nombres del módulo, por ejemplo, m.x = 1 es equivalente a m .__ dict __ [" x "] = 1." (de http://docs.python.org/reference/datamodel.html) – ncoghlan

3

No es necesario utilizar exec para esto, ya que las otras respuestas muestran, pero aquí es el problema con el original código:

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

esto exec A = A, B = B, etc. Si bien esto puede ser interesante si eres un ardiente seguidor del objetivismo, pitón no le importa demasiado para él.

Usted quiere tener las cosas Variable() dentro del ejecutivo para que importa:

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

En el futuro, si usted está tratando de utilizar exec, en primer lugar tratar de no hacerlo. Segundo, imprima lo que está ejecutando, eso lo ayudará a depurar.

+0

No hay votación negativa, pero hay una manera más clara (y probablemente más rápida, si eso importa), tal como se explicita en mi respuesta. – EOL

+0

Por supuesto que existe, digo que no lo haga de esta manera en mi respuesta. Esta es una versión fija del código original que realmente usa 'exec'. – tkerwin

7

El enfoque más limpio, con mucho, que he visto nunca es añadir directamente las variables (es decir, atributos) a su programa (es decir, del módulo principal), como respondida en 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: núcleo de Python los desarrolladores trabajaron duro para hacer posible la modificación de globals() (ver los comentarios a la respuesta de ncoghlan). Entonces, modificar globals() es una alternativa.No estoy seguro de por qué muchas personas sienten que no es tan limpio, aunque (tal vez porque el hecho de que globals() se puede modificar no está documentado explícitamente ).

2

No intente pegar esto en una variable global. Es horrible. Haz esto en su lugar.

import string 

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

El que acceder a él desde variables['Q'], por ejemplo.

Si quiere atribuir el acceso que puede hacer:

class Variables(object): pass 

y

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

Pero en ese caso prefiero crearlos dinámicamente en una clase de variables contenedor.

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) 

Uso:

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

simple y limpia, sin trucos feos (bueno, excepto un getattr, y que no es tan feo), y que ni siquiera tiene que tomar las variables que don no es necesario

+0

Si bien estoy de acuerdo en que este es generalmente el camino a seguir, definitivamente hay casos de uso para agregar muchos objetos directamente al espacio de nombres local, p. para matemáticas x == sin (w) * (y + exp (-z)) es mundos mejor que v.x == m.sin (v.w) * (v.y + m.exp (-v.z)). – DSM

+0

Bueno, creo que la obsesión de los matemáticos con los nombres largos de una letra es un error en primer lugar. :) Es útil cuando haces tus cálculos en papel, o simplificas/expandes fórmulas. ¿Pero en la implementación real de una fórmula en un lenguaje de programación? Nyaaahhhhm escéptico ... :-) –

+2

Tal vez puedas eliminar inmediatamente toda la "v". y M." en mi segunda expresión y veo la primera expresión, pero tuve que compararlos casi carácter por personaje para asegurarme de que fueran lo mismo. Una letra extra para cada variable y función, y un punto que me hace pensar en la multiplicación. Es mucho más probable que omita un error obvio en la segunda forma, ya que tengo que superar años de experiencia leyendo la forma estándar sin personajes extraños esparcidos. La legibilidad cuenta, como escuché a alguien decir en alguna parte ;-), y ese principio no siempre se inclina a favor de más personajes. – DSM

Cuestiones relacionadas