动态全局变量赋值

时间:2010-11-14 22:35:16

标签: python dynamic global-variables variable-assignment

我是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"

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

6 个答案:

答案 0 :(得分:6)

你的问题是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中的下一项重新分配。

总结一下:

如果要将“已修改”字符串分配给列表中的项目,请直接执行:

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 Tutorial

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

答案 1 :(得分:4)

正如我在对您的问题的评论中所说,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中的for循环不会更改func()。此外,您应该知道,这只是一个简单的方法,可以让您的示例代码按照您的需要运行,而不是通过特别好或通用的方式来完成这些事情。

答案 2 :(得分:2)

我不确定你在做什么。 global关键字旨在将全局名称导入当前范围,而不是将本地名称全局化。

答案 3 :(得分:2)

你有两个不同的问题,其中一个出现两次。首先,您试图在列表的元素上使用global,这是无用的。你已经可以了:

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

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

引用的值

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

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

答案 4 :(得分:1)

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

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)

答案 5 :(得分:0)

我不确定你要做什么,但这是使用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)