Atribuição de variables ​​globais dinâmicas

Eu sou novo em python e estou tendo muitos problemas em usar global instrução global .
Aqui está um exemplo 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 é o problema. Como posso resolver isso?

Seu problema é que o Python não funciona da maneira que você pensa.
Então vou tentar explicar o que está acontecendo no seu código, linha por linha.

 mouse = "a" 

Atribui a string “a” ao mouse nome.

 background = "b" 

Atribui a string “b” ao background do nome.

 list_ab = [mouse, background] 

Atribui dois objects, referenciados pelos nomes mouse e background , à lista list_ab .
Como já sabemos, são constantes “a” e “b”. Então você pode simplesmente escrever:

 list_ab = ["a", "b"] 

Agora o loop

 for item in list_ab: 

atribui cada object na lista ao item nome.
Para a primeira iteração do loop, significa item = "a" .

A linha

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

não faz sentido, porque ele tenta dizer ao Python que o item nome é global, enquanto não existe essa variável global declarada.

E para o comportamento mais confuso na linha

  item = "modified" 

você deve apenas entender que enquanto ele atribui a string “modificada” ao item nome, as strings “a” e “b” ainda são as mesmas, e ainda são atribuídas à lista list_ab (e nomes mouse e background , o que você não fez toque também).

O próprio item nome vive apenas no escopo onde foi declarado, quando o loop “for” termina, ele é destruído. Ele também é reatribuído a cada iteração com o próximo item do list_ab .

Resumindo:

Se você deseja atribuir uma string “modificada” aos itens da lista, faça isso diretamente:

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

Se você precisar alterar a variável declarada no escopo global, faça o seguinte:

 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" 

Exemplo baseado na primeira revisão da questão:

Ao invés 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() 

Você pode fazer:

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

Ou se você quiser fazer referência a imagens por nome, você pode colocá-las no 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() 

Mas o mais importante é que as variables ​​globais são uma má ideia . A melhor solução seria usar uma 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() 

Para mais exemplos, consulte o tutorial do Python .

Espero que ajude e seja bem-vindo ao StackOverflow!

Como eu disse no meu comentário à sua pergunta, o list_ab não contém referências ao mouse e ao background . Você pode simular isso até certo ponto, colocando seus nomes na lista, assim:

 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() retorna um object semelhante a um dictionary que representa as ligações de nomes não locais nesse ponto na execução do seu script / módulos. É importante notar que o list_ab não é alterado pelo loop for no func() . Além disso, você deve estar ciente de que isso é apenas uma ilustração de uma maneira simples de fazer com que seu código de exemplo funcione como você queria, e não de uma maneira especialmente boa ou genérica de realizar essas tarefas.

Não tenho certeza do que você está tentando fazer. A palavra-chave global destina-se a importar um nome global para o escopo atual, não para tornar um nome local global.

Você está tendo dois problemas distintos e um deles ocorre duas vezes. A primeira é que você está tentando usar global em elementos de uma lista que é inútil. Você já pode fazer:

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

Isto irá alterar os valores que são referenciados por list_ab qual está mais longe do que o seu código está recebendo agora. Isso funciona porque você não está alterando a binding representada por list_ab e, portanto, não precisa ser global. Você já pode ler uma indexação global e nela é apenas uma pesquisa de item e não (em si) sobrescrever quaisquer ligações. No entanto, não irá realmente alterar quais valores são referenciados por b

A segunda é que, quando você vincula o primeiro e o segundo índices de list_ab a b , cria ligações inteiramente novas, de modo que alterar os valores das ligações na lista não altera os valores referenciados por b . Se você quiser fazer isso, você precisa fazer isso diretamente.

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

Você está correndo para o segundo problema novamente quando tenta modificar os elementos de list_ab , iterando sobre eles. Você pode ver isso mais claramente com o código

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

Novamente, isso ocorre porque você está criando uma nova binding para o valor e, em seguida, modificando essa binding em vez do original.

Se você precisar modificar uma lista enquanto iterar sobre ela, você pode fazer

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

Então, como as coisas estão atualmente atualizando a , b e list_ab , e mantendo seus padrões atuais (ou seja, não introduzindo compreensões), você precisa fazer:

 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 

Isso parece muito feio. Por que você precisa mantê-los como variables ​​livres e em uma lista? Não é apenas uma lista boa o suficiente? Se você precisar acessá-los pelo nome, poderá usar um dictionary:

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

O problema aqui é que você está tentando atualizar variables ​​no local, mas suas funções retornam novas instâncias. Tente algo como isto:

 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 

E se você quiser ser especialmente conciso, aqui está um verso que faz a mesma coisa:

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

Mas, na verdade, se você tiver apenas duas imagens, talvez faça mais sentido fazer isso explicitamente:

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

Eu não tenho certeza do que você está tentando fazer, mas aqui está um exemplo 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) 
    Intereting Posts