Qual é a diferença entre globals (), locals () e vars ()?


146

Qual é a diferença entre globals(), locals()e vars()? O que eles retornam? As atualizações dos resultados são úteis?


pode-se atualizar qualquer um desses itens no python 3 e fazer com que o script realmente funcione?
Charlie Parker

Respostas:


172

Cada um deles retorna um dicionário:

  • globals() sempre retorna o dicionário do espaço para nome do módulo
  • locals() sempre retorna um dicionário do espaço para nome atual
  • vars()retorna um dicionário do espaço para nome atual (se chamado sem argumento) ou o dicionário do argumento.

localse varspoderia usar mais algumas explicações. Se locals()for chamado dentro de uma função, ele atualiza um ditado com os valores do namespace da variável local atual (mais quaisquer variáveis ​​de fechamento) a partir desse momento e o retorna. Várias chamadas para locals()no mesmo quadro de pilha retornam o mesmo ditado toda vez - elas são anexadas ao objeto de quadro de pilha como seu f_localsatributo. O conteúdo do dict é atualizado em cada locals()chamada e f_localsacesso a cada atributo, mas apenas nessas chamadas ou acessos a atributos. Ele não é atualizado automaticamente quando variáveis ​​são atribuídas, e a atribuição de entradas no dict não atribuirá as variáveis ​​locais correspondentes:

import inspect

def f():
    x = 1
    l = locals()
    print(l)
    locals()
    print(l)
    x = 2
    print(x, l['x'])
    l['x'] = 3
    print(x, l['x'])
    inspect.currentframe().f_locals
    print(x, l['x'])

f()

nos dá:

{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2

O primeiro print(l)mostra apenas uma 'x'entrada, porque a atribuição locorre após a locals()chamada. O segundo print(l), depois de ligar locals()novamente, mostra uma lentrada, mesmo que não tenhamos salvado o valor de retorno. O terceiro e o quarto prints mostram que a atribuição de variáveis ​​não é atualizada le vice-versa, mas após o acesso f_locals, as variáveis ​​locais são copiadas locals()novamente.

Duas notas:

  1. Esse comportamento é específico do CPython - outros Pythons podem permitir que as atualizações retornem ao espaço de nomes local automaticamente.
  2. No CPython 2.x, é possível fazer isso funcionar colocando uma exec "pass"linha na função. Isso muda a função para um modo de execução mais antigo e lento, que usa o locals()dict como representação canônica de variáveis ​​locais.

Se locals()for chamado fora de uma função, ele retornará o dicionário real que é o espaço para nome atual. Outras alterações no espaço para nome são refletidas no dicionário e as alterações no dicionário são refletidas no espaço para nome:

class Test(object):
    a = 'one'
    b = 'two'
    huh = locals()
    c = 'three'
    huh['d'] = 'four'
    print huh

nos dá:

{
  'a': 'one',
  'b': 'two',
  'c': 'three',
  'd': 'four',
  'huh': {...},
  '__module__': '__main__',
}

Até agora, tudo o que eu disse locals()também é verdadeiro vars()... aqui está a diferença: vars()aceita um único objeto como argumento e, se você der um objeto, ele retorna o __dict__objeto. Para um objeto típico, __dict__é onde a maioria dos dados de atributo é armazenada. Isso inclui variáveis ​​de classe e globais do módulo:

class Test(object):
    a = 'one'
    b = 'two'
    def frobber(self):
        print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()

o que nos dá:

three

Observe que a função __dict__é seu namespace de atributo, não variáveis ​​locais. Não faria sentido para uma função __dict__armazenar variáveis ​​locais, já que recursão e multithreading significam que pode haver várias chamadas para uma função ao mesmo tempo, cada uma com seus próprios locais:

def f(outer):
    if outer:
        f(False)
        print('Outer call locals:', locals())
        print('f.__dict__:', f.__dict__)
    else:
        print('Inner call locals:', locals())
        print('f.__dict__:', f.__dict__)

f.x = 3

f(True)

o que nos dá:

Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}

Aqui, se fchama recursivamente, de modo que as chamadas internas e externas se sobrepõem. Cada um vê suas próprias variáveis ​​locais quando chama locals(), mas as duas chamam o mesmo f.__dict__e f.__dict__não possuem nenhuma variável local.


4
A parte "e quaisquer atribuições ao dicionário não são refletidas no espaço de nome local real" pode ser redigida um pouco para definir .
Sven Marnach

Curiosamente, você pode acessar variáveis ​​adicionadas a um vars()ou locals()dicionário chamado dentro de uma função, se você usar eval(). EG: def test(): huh = locals(); huh['d'] = 4; print eval('d')imprime 4 quando test()é executado!
Mark Mikofski

1
Na verdade, a atribuição ao dict(retornado por locals()) é refletida no espaço para nome local e as alterações no espaço para nome local são refletidas no dict(no meu python). A única coisa é que a especificação não garante esse comportamento.
skyking

O uso do escopo do nome do termo parece mais fácil para mim do que o namespace .
overexchange

1
@overexchange: import thise no googlesite:docs.python.org namespace
Ethan Furman
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.