Assigning dynamic global variables

I am new to python and I have a lot of problems when using the global statement.
Here is a sample code:

 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" 

This is problem. How can I solve it?

+4
source share
6 answers

Your problem is that Python is not working the way you think.
Therefore, I will try to explain what is happening in your code line by line.

 mouse = "a" 

Assigns the string "a" to the name of the mouse .

 background = "b" 

Names the string "b" background .

 list_ab = [mouse, background] 

Assigns two objects referenced by the names mouse and background to the list_ab list.
As we already know, these are the constants "a" and "b". Therefore, you can simply write:

 list_ab = ["a", "b"] 

Now loop

 for item in list_ab: 

Gives each item in the list the name item .
For the first iteration of the loop, this means item = "a" .

Line

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

does not make sense because it is trying to tell Python that the name item is global, while such a global variable is not declared.

And for the most confusing behavior on the line

  item = "modified" 

you should just understand that although it assigns the string “changed” to the name item , the lines “a” and “b” are all the same and are still tied to list_ab (and the names of mouse and background that you did not touch either) .

The name item lives only in the area where it was declared, when the for loop ends, it is destroyed. It also reassigns each iteration to the next element from list_ab .

Summarizing:

If you want to assign a “modified” string to the items in the list, do this directly:

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

If you need to change a variable declared in the global scope, do the following:

 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" 

An example based on the first revision of a question:

Instead

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

You can do:

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

Or, if you want to refer to images by name, you can put them in a dictionary:

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

But most importantly, global variables are a bad idea . A better solution would be to use a class:

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

See the Python Tutorial for more examples.

Hope this helps, and welcome to StackOverflow!

+5
source

As I said in my comment on your question, list_ab does not contain links to mouse and background . You can mimic this to some extent in this case by putting their names in a list, for example:

 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() returns a dictionary-like object that represents non-local name bindings at this point in your script / modules execution. It is important to note that list_ab not changed by the for loop in func() . You should also know that this is just an illustration of one simple way to make your code sample work the way you want, and not a particularly good or general way to accomplish such things.

+4
source

I'm not sure what you are trying to do. The global intended to import a global name into the current scope, not a local name.

+2
source

You have two problems, and one of them occurs twice. First, you are trying to use global for list items, which is useless. You can already do:

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

This will change the values ​​referenced by list_ab , which is more than what your code is currently receiving. It works because you do not change the binding provided by list_ab , and therefore it should not be global. You can already read the global indexing, and there is only an element search in it and not (by itself) overwrite any bindings. However, this doesn’t actually change which values a and b refer to.

Secondly, when you bind the first and second indexes from list_ab to a and b , it creates completely new bindings, so changing the values ​​of the bindings in the list does not change the values ​​referenced by a and b . If you want to do this, you need to do it directly.

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

The second problem repeats when you try to change the list_ab elements, iterating over them. You can see it more clearly with code

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

Again, this is because you create a new value binding, and then change that binding instead of the original one.

If you need to change the list in place while iterating over it, you can do

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

So, since there are currently updates for a , b and list_ab , and saving your current templates (i.e. not introducing understanding), you need to do:

 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 

It looks pretty ugly. Why do you need to store them as free variables and in a list? Isn't just a list good enough? If you need to access them by name, you can use the dictionary:

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

The problem is that you are trying to update variables in place, but your functions return new instances. Try something like this:

 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 

And if you want to be especially concise, here is a one-line that does the same thing:

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

But in fact, if you have only two images, it might make sense to do this explicitly:

 background = Image_loader(background) mouse = Image_loader(mouse) 
+1
source

I'm not sure what you are trying to do, but here is an example of using 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) 
0
source

All Articles