动态全局变量赋值

发布于 2024-10-01 23:03:03 字数 451 浏览 2 评论 0原文

我是 python 新手,在使用 global 指令时遇到很多麻烦。
这是一个代码示例:

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"

这就是问题所在。我该如何解决?

I'm new in python and I'm having many troubles in using global instruction.
Here is a code example:

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 the problem. How can I solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

止于盛夏 2024-10-08 23:03:03

您的问题是 Python 的工作方式与您想象的不同。
因此,我将尝试逐行解释代码中发生的情况。

mouse = "a"

将字符串“a”分配给名称mouse

background = "b"

将字符串“b”分配给名称background

list_ab = [mouse, background]

将名称为 mousebackground 引用的两个对象分配给列表 list_ab
我们已经知道,它们是常数“a”和“b”。所以你可以这样写:

list_ab = ["a", "b"]

现在循环将

for item in list_ab:

列表中的每个对象分配给名称item
对于第一次循环迭代,它意味着 item = "a"

该行

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

没有意义,因为它试图告诉 Python 名称 item 是全局的,但没有声明这样的全局变量。

对于线上最令人困惑的行为,

    item = "modified"

您应该明白,虽然它将字符串“modified”分配给名称 item,但字符串“a”和“b”仍然相同,并且仍然被分配到列表 list_ab(以及名称 mousebackground,您也没有碰过它们)。

名称 item 本身仅存在于声明它的范围内,当“for”循环结束时,它就会被破坏。
每次迭代时,它也会被重新分配给 list_ab 中的下一个项目。

总结一下:

如果您想将“modified”字符串分配给列表中的项目,请直接执行:

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

如果您需要更改在全局范围内声明的变量,请执行以下操作:

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"

基于问题第一次修订的示例:

而不是

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

您可以这样做:

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

或者如果您想按名称引用图像,您可以将它们放入字典中:

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

但最重要的是,全局变量是个坏主意。更好的解决方案是使用类:

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

有关更多示例,请参阅 Python 教程

希望它对您有所帮助,欢迎来到 StackOverflow!

Your problem is that Python works not the way you think.
So I will try to explain what's going on in your code, line by line.

mouse = "a"

Assigns the string "a" to the name mouse.

background = "b"

Assigns the string "b" to the name background.

list_ab = [mouse, background]

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

list_ab = ["a", "b"]

Now the loop

for item in list_ab:

assigns each object in the list to the name item.
For the first loop iteration, it means item = "a".

The line

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

doesn't make sense, because it tries to tell Python that the name item is global, while there is no such global variable declared.

And for the most confusing behavior on the line

    item = "modified"

you should just understand that while it assigns the string "modified" to the name item, strings "a" and "b" are still the same, and still assigned to the list list_ab (and names mouse and background, which you didn't touch either).

The name item itself lives only in the scope where it was declared, when the "for" loop ends, it's destructed.
It is also reassigned every iteration with the next item from the list_ab.

To sum it up:

If you want to assign "modified" string to the items in the list, do it directly:

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

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

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"

Example based on the first revision of the question:

Instead of

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 reference to images by name, you can put them into 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 bad idea. The 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()

For more examples see Python Tutorial.

Hope it helps, and welcome to StackOverflow!

阳光下慵懒的猫 2024-10-08 23:03:03

正如我在对您的问题的评论中所说,list_ab 不包含对 mousebackground 的引用。在这种情况下,您可以通过将它们的名称放入列表中来在某种程度上进行模拟,如下所示:

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()返回类似字典的内容代表脚本/模块执行中该时刻的非本地名称绑定的对象。需要注意的是,list_ab 不会被 func() 中的 for 循环更改。此外,您还应该意识到,这只是使示例代码按您想要的方式工作的一种简单方法的说明,而不是完成此类事情的特别好的或通用的方法。

As I said in my comment to your question, list_ab does not contain references to mouse and background. You can simulate that to some degree in this case by putting their names in the list, like this:

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 the non-local name bindings at that point in your script/modules's execution. It's important to note that list_ab is not changed by the for loop in func(). Also you should be aware that this is only an illustration of one simple way to make your sample code work like you wanted, not of an especially good or generic way to accomplish such things.

一直在等你来 2024-10-08 23:03:03

我不确定你想做什么。 global 关键字旨在将全局名称导入到当前作用域中,而不是使本地名称成为全局名称。

I am not sure what you are trying do to. The global keyword is intended to import a global name into the current scope, not to make a local name global.

趁年轻赶紧闹 2024-10-08 23:03:03

您遇到两个不同的问题,其中之一出现两次。第一个是您尝试在列表的元素上使用 global ,这是无用的。您已经可以这样做:

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

这将更改 list_ab 引用的值,该值比您的代码现在获得的更远。它之所以有效,是因为您没有更改 list_ab 表示的绑定,因此它不需要是全局的。您已经可以读取全局索引,并且它只是一个项目查找,并且(本身)不会覆盖任何绑定。然而,它实际上不会改变 ab 引用的值

第二个是当您将 list_ab 的第一个和第二个索引绑定到ab,它创建全新的绑定,因此更改列表中绑定的值不会更改 a 引用的值和b。如果你想这样做,你需要直接这样做。

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

当您尝试通过迭代来修改 list_ab 的元素时,您会再次遇到第二个问题。您可以通过代码更清楚地看到它

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

。再次,出现这种情况是因为您正在创建一个到该值的新绑定,然后修改绑定而不是原始绑定。

如果您需要在迭代列表时就地修改列表,您可以执行以下

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

操作,因此目前的情况是更新 ablist_ab,并保持当前的模式(即不引入推导式),您需要这样做:

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

这看起来很丑陋。为什么需要将它们保留为自由变量并保存在列表中?仅仅列出一个清单还不够吗?如果您需要按名称访问它们,则可以使用字典:

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

print dict_ab['a']
print dict_ab['b']

You are having two distinct problems and one of them occurs twice. The first is that you are attempting to use global on elements of a list which is useless. You can already do:

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

This will change the values which are referenced by list_ab which is further than your code is getting now. It works because you are not changing the binding represented by list_ab and so it doesn't need to be global. You can already read a global indexing and into it is just an item lookup and doesn't (in itself) overwrite any bindings. However it will not actually change which values are referenced by a and b

The second is that when you bind the first and second indices of list_ab to a and b, it creates entirely new bindings so that changing the values of the bindings in the list does nothing to change the values referenced by a and b. If you want to do that, you need to do it directly.

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

You are running into the second problem again when you try to modify the elements of list_ab by iterating over them. You can see it more clearly with the code

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

Again, this occurs because you are creating a new binding to the value and then modifying that binding instead of the original one.

If you need to modify a 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 as things currently stand to update a, b and list_ab, and keeping your current patterns (i.e. not introducing comprehensions), 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

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

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

print dict_ab['a']
print dict_ab['b']
拥抱没勇气 2024-10-08 23:03:03

这里的问题是您试图就地更新变量,但您的函数返回新实例。尝试这样的事情:

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

如果你想特别简洁,这里有一个单行代码可以做同样的事情:

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

但实际上,如果你只有两个图像,那么明确地这样做可能更有意义:

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

The issue here is that you're 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's a one-liner that does the same thing:

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

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

background = Image_loader(background)
mouse = Image_loader(mouse)
风月客 2024-10-08 23:03:03

我也不确定你想做什么,但这里有一个使用 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)

I'm not sure what you are trying to do either, but here's 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文