Como não havia uma resposta completa sobre o tempo do Python3, fiz uma resposta aqui. A maior parte do que é descrito aqui está detalhada na 4.2.2 Resolução de nomes da documentação do Python 3.
Conforme fornecido em outras respostas, existem 4 escopos básicos, o LEGB, para Local, Enclosing, Global e Builtin. Além desses, há um escopo especial, o corpo da classe , que não compreende um escopo anexo para os métodos definidos na classe; quaisquer atribuições no corpo da classe fazem com que a variável a partir daí seja vinculada no corpo da classe.
Especialmente, nenhuma declaração de bloco, além de def
e class
, cria um escopo variável. No Python 2, a compreensão da lista não cria um escopo de variável, no entanto, no Python 3, a variável de loop nas compreensões da lista é criada em um novo escopo.
Demonstrar as peculiaridades do corpo de classe
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Assim, diferentemente do corpo da função, você pode reatribuir a variável ao mesmo nome no corpo da classe, para obter uma variável de classe com o mesmo nome; outras pesquisas sobre esse nome são resolvidas para a variável de classe.
Uma das maiores surpresas para muitos iniciantes no Python é que um for
loop não cria um escopo variável. No Python 2, as compreensões da lista também não criam um escopo (enquanto os geradores e as compreensões de ditado criam!) Em vez disso, elas vazam o valor na função ou no escopo global:
>>> [ i for i in range(5) ]
>>> i
4
As compreensões podem ser usadas como uma maneira astuta (ou péssima, se você desejar) de criar variáveis modificáveis nas expressões lambda no Python 2 - uma expressão lambda cria um escopo de variável, como a def
instrução faria, mas no lambda nenhuma instrução é permitida. A atribuição sendo uma instrução em Python significa que nenhuma atribuição de variável no lambda é permitida, mas a compreensão da lista é uma expressão ...
Esse comportamento foi corrigido no Python 3 - nenhuma expressão de compreensão ou geradores vazam variáveis.
O global realmente significa o escopo do módulo; o principal módulo python é o __main__
; todos os módulos importados são acessíveis através da sys.modules
variável; para ter acesso a __main__
um pode usar sys.modules['__main__']
, ou import __main__
; é perfeitamente aceitável acessar e atribuir atributos lá; eles aparecerão como variáveis no escopo global do módulo principal.
Se um nome for designado no escopo atual (exceto no escopo da classe), ele será considerado pertencente a esse escopo; caso contrário, será considerado pertencente a qualquer escopo que atribua à variável (ele pode não ser atribuído ainda, ou de modo algum) ou, finalmente, o escopo global. Se a variável for considerada local, mas ainda não estiver definida ou tiver sido excluída, a leitura do valor da variável resultará em UnboundLocalError
, que é uma subclasse de NameError
.
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
O escopo pode declarar que deseja explicitamente modificar a variável global (escopo do módulo), com a palavra-chave global:
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
Isso também é possível, mesmo que tenha sido sombreado no escopo anexo:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
No python 2, não há maneira fácil de modificar o valor no escopo anexo; geralmente isso é simulado por ter um valor mutável, como uma lista com comprimento 1:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
No entanto, em python 3, o nonlocal
vem para resgatar:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
A nonlocal
documentação diz que
Os nomes listados em uma declaração não-local, diferentemente dos listados em uma declaração global, devem se referir a ligações preexistentes em um escopo anexo (o escopo no qual uma nova ligação deve ser criada não pode ser determinado sem ambiguidade).
ie nonlocal
sempre se refere ao escopo não global externo mais interno ao qual o nome foi vinculado (isto é, atribuído a, inclusive usado como for
variável de destino, na with
cláusula ou como parâmetro de função).
Qualquer variável que não seja considerada local para o escopo atual, ou qualquer escopo anexo, é uma variável global. Um nome global é pesquisado no dicionário global do módulo; se não encontrado, o global é pesquisado a partir do módulo builtins; o nome do módulo foi alterado de python 2 para python 3; no python 2 era __builtin__
e no python 3 agora é chamado builtins
. Se você atribuir a um atributo do módulo builtins, ele será visível a seguir para qualquer módulo como uma variável global legível, a menos que esse módulo os sombreie com sua própria variável global com o mesmo nome.
A leitura do módulo interno também pode ser útil; suponha que você queira a função de impressão no estilo python 3 em algumas partes do arquivo, mas outras partes do arquivo ainda usem a print
instrução No Python 2.6-2.7, você pode se apossar da print
função Python 3 com:
import __builtin__
print3 = __builtin__.__dict__['print']
Na from __future__ import print_function
verdade, ele não importa a print
função em nenhum lugar do Python 2 - apenas desabilita as regras de análise para print
instrução no módulo atual, manipulando print
como qualquer outro identificador de variável e, assim, permitindo que print
a função seja pesquisada nos componentes internos.