Diga aí, o que você acha que o código abaixo irá imprimir na tela?
def func():
print x
x = 42
func()
A resposta é óbvia: 42. OK, sem pegadinhas por enquanto. E o código abaixo, o que irá imprimir?
def func():
print x
x = 1
x = 42
func()
Pelo que sabemos até então, somos levados a crer que o código acima irá imprimir 42 na tela, correto? Mas, veja a saída que recebemos na cabeça ao executar o código:
Traceback (most recent call last):
File "<pyshell#3>", line 6, in
func()
File "<pyshell#3>", line 2, in func
print x
UnboundLocalError: local variable 'x' referenced before assignment
UnboundLocalError significa que estamos acessando uma variável antes dela ter sido criada no escopo da função func(). A linha que está gerando o erro é a linha 2, que contém print x. Entretanto, observe com cuidado os dois exemplos de código acima. No primeiro deles também estamos fazendo print x na primeira linha da função. Inclusive, o valor impresso pela função foi o valor da variável x definida no escopo global.
A culpada por esse erro é a linha 3 (x = 1) e a explicação é simples: o código da função é analisado e x é definido estaticamente pelo compilador como uma variável (ou melhor, como um nome) local ao escopo da função quando este encontra a atribuição x = 1. E isso vale para a função inteira, mesmo que a atribuição ocorra somente na última linha dela. Essa análise é feita estaticamente durante a criação da função func, quando o compilador encontra a declaração de criação de função def. Assim, mais tarde quando func() é chamada, print x tenta imprimir o valor de uma variável local antes dela ter algum valor atribuído a si.
Existe uma regra bem simples:
Sempre que o compilador encontra uma atribuição a um nome dentro de uma função, ele assume que tal nome é local em toda a função, não importando onde a atribuição ocorre.
O código a seguir funciona
def func():
x = 1
print x
x = 42
func()
mas imprime 1, pois ao encontrar x = 1, o compilador assume que x é uma variável local. Mas e se precisarmos alterar o valor do x global dentro da função? Antes de qualquer coisa, vamos ver se o x global (de valor 42, inicialmente) é alterado:
def func():
x = 1
print x
x = 42
func()
print x
O programa acima irá imprimir:
1
42
Ou seja, o x global não foi alterado. Se quiser mesmo alterar o valor de uma variável global dentro de uma função, Python exige que identifiquemos a mesma como global dentro da função. Isso pode ser feito com a estranhíssima construção global:
def func():
global x
x = 1
print x
x = 42
func()
print x
O código acima imprime:
1
1
Ou seja, a global x foi alterada pela atribuição feita dentro de func().
ALERTA: criar variáveis globais e alterar o valor delas dentro de funções é uma péssima prática. O código fica mais difícil de ler e modificar (você precisa saber todos os lugares onde a variável global está sendo usada) e pode levar a bugs bem difíceis de serem encontrados. Não é por menos que Python força o programador a explicitar a referência a uma variável global quando quiser alterá-la fora do escopo global. Soa quase como uma autodeclaração do programador: “sim, eu sou tosco e estou prestes a fazer mer** no meu código”. 😀

Você precisa fazer login para comentar.