Asignación dinámica de variables globales

Soy nuevo en Python y tengo muchos problemas para usar global instrucción global .
Aquí hay un ejemplo de código:

 mouse = "a" background = "b" list_ab = [mouse, background] def func (): for item in list_ab: global item # I want to modify the GLOBAL item, which is mouse # and background. item = "modified" print mouse # must be "modified" not "a" print background # must be "modified" not "b" 

Este es el problema. ¿Cómo puedo resolverlo?

Su problema es que Python no funciona como usted piensa.
Así que trataré de explicar lo que está pasando en su código, línea por línea.

 mouse = "a" 

Asigna la cadena “a” al nombre del mouse .

 background = "b" 

Asigna la cadena “b” al background nombre.

 list_ab = [mouse, background] 

Asigna dos objetos, referenciados por los nombres del mouse y el background , a la lista list_ab .
Como ya sabemos, son las constantes “a” y “b”. Así que solo puedes escribir:

 list_ab = ["a", "b"] 

Ahora el bucle

 for item in list_ab: 

asigna cada objeto en la lista al item nombre.
Para la primera iteración de bucle, significa item = "a" .

La línea

  global item # I want to modify the GLOBAL item, which is mouse ad background 

no tiene sentido, porque trata de decirle a Python que el item del nombre es global, mientras que no hay una variable global declarada.

Y para el comportamiento más confuso en la línea.

  item = "modified" 

solo debes entender que mientras asigna la cadena “modificada” al item del nombre, las cadenas “a” y “b” siguen siendo las mismas, y aún están asignadas a la lista list_ab (y nombres mouse y background , que no tocar tampoco).

El item nombre en sí vive solo en el ámbito en el que se declaró, cuando el bucle “para” finaliza, se destruye. También se reasigna cada iteración con el siguiente elemento de list_ab .

Para resumirlo:

Si desea asignar una cadena “modificada” a los elementos de la lista, hágalo directamente:

 list_ab[0] = "modified" list_ab[1] = "modified" 

Si necesita cambiar la variable declarada en el ámbito global, haga lo siguiente:

 mouse = "a" def func(): global mouse # tell Python that you want to work with global variable mouse = "modified" func() print mouse # now mouse is "modified" 

Ejemplo basado en la primera revisión de la pregunta:

En lugar de

 background = g_base("bg.jpg") # g_base class instance mouse = g_base("mouse.png",alpha=1) # g_base class instance imgs_to_load = [mouse, background] def Image_loader (img): # ..... code to load the image and convert it into pygame surface... return img_load def main (): for image in img_to_load: global image image = Image_loader (img) print image # if I print image, it is a pygame surface print background # But here, outside the loop, image is still a g_base instance ?!?! print mouse # " " main() 

Tu puedes hacer:

 imgs_to_load = [g_base("bg.jpg"), g_base("mouse.png",alpha=1)] # list with a g_base class instances def Image_loader(img): # ..... code to load the image and convert it into pygame surface... return img_load def main (): imgs_in_pygame_format = [] # create an empty list for image in imgs_to_load: loaded_image = Image_loader(image) imgs_in_pygame_format.append(loaded_image) # add to the list for image in imgs_in_pygame_format: print image # every image in the list is a pygame surface # or print image[0] print image[1] main() 

O si desea hacer referencia a las imágenes por nombre, puede ponerlas en el diccionario:

 imgs_to_load = {} imgs_to_load["bg"] = g_base("bg.jpg") imgs_to_load["mouse"] = g_base("mouse.png",alpha=1) imgs_in_pygame_format = {} # create a global dictionary for loaded images def main (): global imgs_in_pygame_format # import that global name into the local scope for write access for name, data in imgs_to_load.items(): imgs_in_pygame_format[name] = Image_loader(data) # add to the dictionary for image in imgs_in_pygame_format: print image # every image in the dictionary is a pygame surface # or print imgs_in_pygame_format["bg"] print imgs_in_pygame_format["mouse"] main() 

Pero lo más importante, las variables globales son una mala idea . La mejor solución sería usar una clase:

 def Image_loader(img): # ..... code to load the image and convert it into pygame surface... return img_load class Image: def __init__(self, image): self.data = Image_loader(image) def main (): bg = Image(g_base("bg.jpg")) mouse = Image(g_base("mouse.png",alpha=1)) print bg.data print mouse.data main() 

Para más ejemplos ver tutorial de Python .

Espero que ayude, y bienvenido a StackOverflow!

Como dije en mi comentario a su pregunta, list_ab no contiene referencias al mouse y al background . Puede simular eso hasta cierto punto en este caso al poner sus nombres en la lista, de esta manera:

 mouse = "a" background = "b" list_ab = ['mouse', 'background'] def func(): for name in list_ab: globals()[name] = "modified" print mouse # must be "modified" not "a" print background # must be "modified" not "b" func() # modified # modified 

globals() devuelve un objeto similar a un diccionario que representa los enlaces de nombres no locales en ese punto en la ejecución de su script / módulos. Es importante tener en cuenta que el bucle for en func() no modifica list_ab . Además, debe tener en cuenta que esto es solo una ilustración de una forma sencilla de hacer que su código de muestra funcione como usted desea, no de una manera especialmente buena o genérica para lograr tales cosas.

No estoy seguro de lo que estás tratando de hacer. La palabra clave global está destinada a importar un nombre global en el ámbito actual, no para hacer un nombre local global.

Tiene dos problemas distintos y uno de ellos ocurre dos veces. La primera es que está intentando usar elementos global en una lista que no sirve para nada. Ya puedes hacer:

 def func(): list_ab[0] = 'modified' list_ab[1] = 'modified' 

Esto cambiará los valores a los que hace referencia list_ab que está más lejos de lo que su código está obteniendo ahora. Funciona porque no está cambiando el enlace representado por list_ab y, por lo tanto, no necesita ser global. Ya puede leer una indexación global y en ella es solo una búsqueda de elementos y no (en sí) sobrescribe ningún enlace. Sin embargo, no cambiará realmente a qué valores se hace referencia por a y b

La segunda es que cuando se unen los primeros y segundos índices de list_ab a a y b , se crean enlaces completamente nuevos, de modo que al cambiar los valores de los enlaces en la lista no se hace nada para cambiar los valores a los que hace referencia a y b . Si quieres hacer eso, necesitas hacerlo directamente.

 def func(): global a, b a = 'modified' b = 'modified' 

Se está ejecutando nuevamente en el segundo problema cuando intenta modificar los elementos de list_ab iterando sobre ellos. Puedes verlo más claramente con el código.

 def func(): list_ab = ['a', 'b'] for item in list_ab: item = 'modified' print list_ab # prints ['a', 'b'] 

De nuevo, esto ocurre porque está creando un nuevo enlace al valor y luego modificando ese enlace en lugar del original.

Si necesita modificar una lista en su lugar mientras está iterando sobre ella, puede hacerlo

 def func(): list_ab = ['a', 'b'] for i in xrange(len(list_ab)): list_ab[i] = 'modified' 

Por lo tanto, como las cosas actualmente se actualizan para actualizar a , b y list_ab , y mantener sus patrones actuales (es decir, no introducir comprensiones), debe hacer:

 def func(): global a, b for i in xrange(len(list_ab)): list_ab[i] = 'modified' a = 'modified' b = 'modified' print list_ab print a, b 

Eso se ve bastante feo. ¿Por qué necesitas mantenerlas como variables libres y en una lista? ¿No es una lista lo suficientemente buena? Si necesita acceder a ellos por nombre, puede usar un diccionario:

 dict_ab = {'a': 'a', 'b': 'b'} for key in dict_ab: dict_ab[key] = modified print dict_ab['a'] print dict_ab['b'] 

El problema aquí es que está intentando actualizar las variables en el lugar, pero sus funciones devuelven instancias nuevas. Intenta algo como esto:

 def main (): converted_images = [] for image in [mouse, background]: converted_images.append(Image_loader(img)) # now re-assign the pygame surfaces to the old names background, mouse = converted_images 

Y si quieres ser especialmente conciso, aquí hay una frase que hace lo mismo:

 background, mouse = [Image_loader(img) for img in [background, mouse]] 

Pero realmente, si solo tiene dos imágenes, podría tener más sentido hacer esto explícitamente:

 background = Image_loader(background) mouse = Image_loader(mouse) 

Tampoco estoy seguro de lo que intentas hacer, pero aquí hay un ejemplo de uso global :

 value = 7 def display(): print value # global values are read-only any time def increment(): global value # must declare global to write it value += 1 def local(): value = 9 # this is a local value print value increment() # changes global value to 8 display() # displays it local() # changes local value to 9 and displays it print value # displays global value (still 8)