Pular para o conteúdo

Fundamentos

Escopo de variáveis em Python: local, global e nonlocal

Entenda o escopo de variáveis em Python: nomes locais e globais, a ordem de busca, o erro de variável local sem valor e quando usar global e nonlocal.

Por Prof. Rodrigo Faustino · Atualizado em · 14 min de leitura

Escopo é a região do programa onde um nome existe e pode ser usado. Uma variável criada dentro de uma função é local: só existe enquanto a função roda e só é vista de dentro dela. Uma variável criada no corpo do arquivo, fora de qualquer função, é global e pode ser lida em qualquer lugar. Quando uma função precisa alterar uma variável de fora, e não só lê-la, ela declara isso com global, para um nome do arquivo, ou nonlocal, para um nome de uma função que a envolve.

Até aqui, as funções da série receberam tudo por parâmetro e entregaram tudo por return, e as variáveis de dentro e de fora tinham nomes parecidos sem que isso importasse. Este artigo explica por que isso funcionou, onde está o limite e o que fazer quando a função precisa de memória entre uma chamada e outra, como acontece em programas de ESP32 que contam apertos de botão. Veremos as regras de visibilidade, os erros que elas provocam e quando vale e quando não vale usar global.

Variável local: nasce e morre com a função

def calcular():
    resultado = 42
    print("dentro:", resultado)

calcular()
print("fora:", resultado)

A saída tem uma linha certa e depois um erro:

dentro: 42
Traceback (most recent call last):
  File "main.py", line 6, in <module>
NameError: name 'resultado' isn't defined

Na primeira linha da saída, o print de dentro encontrou resultado. O print de fora, na linha 6, não. A variável foi criada durante a chamada de calcular() e desapareceu quando a função terminou. Fora dela, o nome simplesmente não existe, e o Python acusa NameError.

Os parâmetros seguem a mesma regra, porque são variáveis locais que já nascem com valor:

def fazer2(a, b):
    c = a + b
    print(c)

fazer2(1, 2)
print(a)
3
Traceback (most recent call last):
  File "main.py", line 6, in <module>
NameError: name 'a' isn't defined

O a, o b e o c só existem dentro de fazer2. Esse isolamento é uma vantagem: duas funções diferentes podem usar i, total ou n sem atrapalhar uma à outra, e o autor de uma função não precisa conhecer as variáveis das outras. É o que dá sentido à ideia de "dividir para conquistar" dos artigos anteriores.

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

Variável global: lida de qualquer lugar

Tudo que é criado no corpo do arquivo, fora de funções, é global. Qualquer função pode ler esses nomes sem nenhuma preparação:

limite = 100

def mostrar():
    print("limite dentro:", limite)

mostrar()
print("limite fora:", limite)

A saída é limite dentro: 100 e limite fora: 100. A função não tem limite próprio, então o Python procura fora dela e encontra o do arquivo. Para ler, nada mais é necessário. Isso já vinha funcionando nos exemplos com led = Pin(2, Pin.OUT) do artigo sobre funções, em que piscar() usava um led criado fora.

O que acontece ao atribuir dentro da função

Três quadros lado a lado mostrando a variável total em dois lugares. Antes da chamada, só existe a sala global com total igual a 10 e a sala local aparece tracejada, como inexistente. Dentro de mexer, a sala global continua com 10 e uma sala local nova tem total igual a 99, e o print mostra 99. Depois da chamada, a sala local sumiu e print de total mostra 10. Uma faixa diz que atribuir dentro da função cria um nome local e deixa o global intocado.
A atribuição dentro da função cria um total local e deixa o global como estava.

O problema começa na atribuição. Se a função escreve total = 99 e já existe um total fora, o Python não altera o de fora: cria um novo, local.

total = 10

def mexer():
    total = 99
    print("dentro:", total)

mexer()
print("fora:", total)

A saída é dentro: 99 e fora: 10. São dois total diferentes, cada um em sua sala, como mostra a figura. Durante a chamada, o nome total dentro da função aponta para a sala local, que tem 99. Quando a função termina, a sala local some, e o total global continua com o valor que sempre teve.

A regra do Python é: se um nome recebe valor em qualquer ponto da função, ele é local em toda a função. Dessa regra sai o erro mais confuso do assunto.

O erro da variável local sem valor

contador = 0

def somar_um():
    contador = contador + 1

somar_um()
Traceback (most recent call last):
  File "main.py", line 6, in <module>
  File "main.py", line 4, in somar_um
NameError: local variable referenced before assignment

A intenção era somar 1 ao contador do arquivo. Mas o contador = ... marca o nome como local, e, ao calcular o lado direito, o Python procura o contador local, que ainda não tem valor. O Python do computador usa um nome mais específico para esse erro, UnboundLocalError, e um texto com o nome da variável: local variable 'contador' referenced before assignment. O simulador mostra NameError com a versão curta.

O mesmo erro aparece quando a função lê o nome antes de atribuí-lo, mesmo que exista um global com esse nome:

x = 1

def f():
    print(x)
    x = 2

f()
Traceback (most recent call last):
  File "main.py", line 7, in <module>
  File "main.py", line 4, in f
NameError: local variable referenced before assignment

O x = 2 na linha 5 torna o x local na função inteira, inclusive no print(x) da linha 4, que vem antes. O Python decide quem é local antes de rodar a função, olhando o corpo todo.

Quatro níveis e a ordem da busca

Quatro caixas aninhadas, da maior para a menor: embutidos com print, len e range; global com limite igual a 100; função externa com total igual a 0; função interna com parcial igual a 5 e um print que usa parcial, total e limite. À direita, uma lista numerada mostra a ordem da busca de um nome: local, externa, global e embutido, com um exemplo de nome achado em cada nível. Uma faixa diz que o Python procura de dentro para fora e para no primeiro nome que encontra.
Os quatro níveis de escopo e a ordem em que o Python procura um nome.

Funções podem ser definidas dentro de outras funções, e o Python tem uma ordem fixa para procurar um nome, conhecida pelas iniciais LEGB:

  1. Local: o corpo da função que está rodando.
  2. Enclosing: as funções que envolvem esta, da mais próxima para a mais distante.
  3. Global: o arquivo.
  4. Built-in: os nomes embutidos, como print, len e range.

A busca vai de dentro para fora e para no primeiro lugar em que o nome aparece:

x = "global"

def externa():
    x = "enclosing"
    def interna():
        x = "local"
        print("interna ve", x)
    interna()
    print("externa ve", x)

externa()
print("arquivo ve", x)

def sem_local():
    print("sem local ve", x)

sem_local()

A saída é interna ve local, externa ve enclosing, arquivo ve global e sem local ve global. Cada função enxerga o x do seu nível. A sem_local não tem x próprio nem função externa, então cai no global.

A última camada, a dos nomes embutidos, explica uma armadilha: nomes como sum, max e min são funções comuns, e dá para cobri-las por engano com uma variável.

def f():
    max = 3
    print("local", max)

f()
print(max(4, 9))

A saída é local 3 e 9. Dentro de f, o max cobriu a função embutida, mas só ali, e fora dela max(4, 9) continua funcionando. Já no escopo global, o estrago fica no arquivo inteiro:

sum = 0
print(sum([1, 2, 3]))
Traceback (most recent call last):
  File "main.py", line 2, in <module>
TypeError: 'int' object isn't callable

O nome sum passou a guardar o número 0, e o sum([1, 2, 3]) tenta chamar um número. A mensagem do Python do computador é 'int' object is not callable. Se uma função embutida "parou de funcionar", procure uma variável com o mesmo nome.

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

Não existe escopo de bloco

Em muitas linguagens, uma variável criada dentro de um if ou de um for morre no fim do bloco. No Python, só funções criam escopo. Os blocos de if, for e while não:

for i in range(3):
    dobro = i * 2
print(i, dobro)

if i > 0:
    msg = "positivo"
print(msg)

while True:
    achou = 7
    break
print(achou)

A saída é 2 4, positivo e 7. O i e o dobro do laço continuam existindo depois dele, com o valor da última volta. A variável msg, criada dentro do if, é visível fora. Isso é cômodo e perigoso ao mesmo tempo: se o bloco não rodar, a variável nunca nasce.

if False:
    x = 1
print(x)
Traceback (most recent call last):
  File "main.py", line 3, in <module>
NameError: name 'x' isn't defined

O caso real é o if que só atribui em uma condição e uma linha mais abaixo usa a variável sem pensar nos outros caminhos. A solução é dar um valor inicial antes do if, como msg = "", ou garantir que todos os caminhos atribuem.

global: alterar uma variável do arquivo

Quando a função precisa mesmo mudar um nome do arquivo, ela o declara com global antes de usar:

contador = 0

def somar_um():
    global contador
    contador = contador + 1

somar_um()
somar_um()
somar_um()
print(contador)

A saída é 3. O global contador avisa ao Python: "este nome não é local, é o do arquivo". A partir daí, a atribuição altera o contador global, e as três chamadas acumulam. Sem a declaração, o resultado seria o erro da seção anterior.

O global só é necessário para reatribuir um nome. Alterar o conteúdo de uma lista, por exemplo, não é reatribuir:

lista = [1, 2]

def acrescentar():
    lista.append(3)

acrescentar()
print(lista)

def trocar():
    lista = [9, 9]
    print("dentro", lista)

trocar()
print("fora", lista)

def trocar2():
    global lista
    lista = [9, 9]

trocar2()
print("depois de trocar2", lista)

A saída é [1, 2, 3], dentro [9, 9], fora [1, 2, 3] e depois de trocar2 [9, 9]. A acrescentar funcionou sem global, porque lista.append(3) usa o nome para chegar à lista e a modifica, sem ligar o nome a outro objeto. A trocar fez lista = [9, 9], uma atribuição, e criou uma lista local. Só a trocar2, com global, substituiu a lista do arquivo. A regra: global é para reatribuir, e métodos que modificam o objeto no lugar dispensam.

Algumas regras de sintaxe, com os erros de quem as quebra. A declaração tem de vir antes do uso do nome na função, e um parâmetro não pode ser declarado global:

def f():
    x = 1
    global x
Traceback (most recent call last):
  File "main.py", line 3
SyntaxError: identifier redefined as global

O Python do computador explica melhor: name 'x' is assigned to before global declaration. O mesmo erro aparece com def f(n): global n. Por fim, a declaração pode listar vários nomes, como global maior, menor, e pode criar um global que ainda não existia:

def f():
    global z
    z = 5

f()
print(z)

A saída é 5. É permitido, mas é um estilo ruim, porque quem lê o arquivo não vê onde z nasce.

nonlocal: alterar o nome de uma função externa

Três colunas com versões de uma função que soma um a uma variável de fora. Na primeira, sem declarar nada, a atribuição cria um nome local sem valor e o resultado é NameError. Na segunda, com global contador, a função altera o nome do arquivo e contador vale 3 depois de três chamadas. Na terceira, uma função interna com nonlocal total altera o total da função externa, que vale 8. Uma faixa diz que ler um nome de fora é livre e reatribuir exige global ou nonlocal.
Sem declaração dá erro. Com global ou nonlocal, a função altera o nome de fora.

Em funções aninhadas, o global não serve, porque o nome que se quer mudar não está no arquivo, e sim na função externa. Para esse caso existe o nonlocal:

def externa():
    total = 0
    def somar(x):
        nonlocal total
        total = total + x
    somar(5)
    somar(3)
    print("total", total)

externa()

A saída é total 8. A função somar altera o total da externa. Sem o nonlocal, o resultado seria o mesmo erro da variável local sem valor:

def externa():
    total = 0
    def somar(x):
        total = total + x
    somar(5)
    print("total", total)

externa()
Traceback (most recent call last):
  File "main.py", line 8, in <module>
  File "main.py", line 5, in externa
  File "main.py", line 4, in somar
NameError: local variable referenced before assignment

O nonlocal exige que o nome já exista numa função externa. Se não existir, o erro vem antes de rodar:

def f():
    nonlocal y
    y = 1
Traceback (most recent call last):
  File "main.py", line 1
SyntaxError: no binding for nonlocal found

O Python do computador diz no binding for nonlocal 'y' found, com o nome. A figura reúne as três situações: sem declaração, com global e com nonlocal.

Uma aplicação do nonlocal é a função que carrega um estado próprio entre chamadas, sem usar global. Funções ainda não foram usadas como valores nesta série, então este trecho é uma amostra para quem quiser ir além:

def contador():
    n = 0
    def passo():
        nonlocal n
        n += 1
        return n
    return passo

a = contador()
b = contador()
print(a(), a(), a())
print(b())

A saída é 1 2 3 e 1. A função contador devolve a passo, e cada contador criado leva consigo o próprio n. O a e o b não se atrapalham. Se isso parecer demais por enquanto, pule: o essencial é saber o que o nonlocal faz.

Quando usar global, e quando evitar

Variáveis globais são tentadoras porque eliminam parâmetros: qualquer função enxerga e muda tudo. O custo é que o comportamento de cada função passa a depender de um estado espalhado, e para entender uma função é preciso saber o que todas as outras fizeram com aquele nome antes. Testar sozinha também deixa de ser possível.

A alternativa é a que o artigo anterior defendeu: a função recebe o valor por parâmetro e entrega o novo por return.

def contar(n):
    return n + 1

apertos = 0
apertos = contar(apertos)
apertos = contar(apertos)
apertos = contar(apertos)
print("total", apertos)

A saída é total 3. Quem chama decide onde guardar, e a função pode ser testada com qualquer valor. É o caminho preferido sempre que for possível.

Há três usos legítimos de nomes globais. O primeiro são as constantes, valores que não mudam durante o programa e que, por convenção, se escrevem em maiúsculas:

LIMITE = 100
VEZES = 3

def piscar():
    for i in range(VEZES):
        print("pisca", i + 1)
    print("limite", LIMITE)

piscar()

A saída é pisca 1, pisca 2, pisca 3 e limite 100. Só leitura, sem global, e o nome em maiúsculas avisa ao leitor que não deve ser alterado. O segundo são os objetos de hardware criados uma vez, como led = Pin(2, Pin.OUT), que várias funções usam. O terceiro é o estado que precisa sobreviver entre chamadas quando não há quem receba um return, que é o caso dos callbacks.

Na ESP32: estado e callbacks

Um programa de ESP32 costuma ter um laço principal e funções que reagem a eventos: um botão foi apertado, um temporizador estourou. Essas funções são chamadas pelo sistema, e não por você, então não há quem receba o return. Para registrar o que aconteceu, elas alteram uma variável do arquivo:

apertos = 0

def ao_apertar():
    global apertos
    apertos += 1
    print("aperto", apertos)

ao_apertar()
ao_apertar()
ao_apertar()
print("total", apertos)

A saída é aperto 1, aperto 2, aperto 3 e total 3. Aqui as chamadas são manuais, para o exemplo rodar sem circuito, mas o formato é o de uma função de tratamento de evento: um global, uma atualização e nada de return. O laço principal lê apertos quando quiser. O artigo sobre programar sem travar mostra como organizar esse estado, com temporizadores e máquinas de estados, e vale como continuação.

Quando a função é chamada por você, no laço principal, o caminho de parâmetro e return continua melhor. Em ambos os casos, o global só deve aparecer onde for imprescindível, e o nome da variável deve dizer o que ela guarda.

Erros comuns e como reconhecê-los

Os erros deste artigo se dividem em dois grupos. Os de execução, NameError por nome que não existe ou que é local sem valor, e TypeError por um nome embutido coberto. Os de sintaxe, global depois do uso, nonlocal sem nome externo. A mensagem do simulador é, em vários casos, mais curta que a do Python do computador, e a linha apontada é a que ajuda: no erro de variável local, o que importa é a linha da atribuição dentro da função.

Em sala de aula: onde o escopo costuma tropeçar

Estes casos se repetem nas turmas.

Esperar que a variável de dentro exista fora

O aluno calcula media dentro de uma função e usa media depois, no programa. O NameError aparece, e a conclusão é que "a variável sumiu". A resposta é o return: a função entrega o valor, e quem chamou o guarda.

O contador que não conta

A função somar_um do começo. O aluno acrescenta o contador = contador + 1 dentro da função e recebe um erro, que não entende, porque "o contador existe, está bem ali em cima". O que falta é a pergunta: esta função atribui a este nome? Se sim, ele é local, a menos que se diga o contrário.

O global espalhado por tudo

Depois de descobrir o global, o aluno o usa em todas as funções, para todas as variáveis, e para de usar parâmetros. O programa funciona, mas fica impossível de ler: nenhuma função diz do que depende. A solução é voltar a parâmetros e return, e deixar o global para o que realmente precisa sobreviver.

Dar a uma variável o nome de uma função embutida

Quem escolhe sum, max, min, list ou len como nome de variável cobre a função pronta. A mensagem, 'int' object isn't callable, aparece longe da causa. Um nome melhor, como soma ou maior, evita o problema.

Achar que o if e o for criam escopo

O aluno que vem de outra linguagem espera que a variável do laço sumisse no fim e se surpreende ao vê-la viva. O que costuma morder é o contrário: usar uma variável criada num if que não rodou.

Parâmetro e variável de fora com o mesmo nome

É o caso do dobrar(n) do artigo anterior. O aluno vê dois n e acha que são o mesmo. A saída que mais ajuda é desenhar as salas da figura: cada função tem a sua.

Exercício: menor e maior de uma sequência

Escreva uma função registrar(valor) que atualiza duas variáveis do arquivo, menor e maior, a cada valor recebido, e depois reescreva a mesma lógica sem global, devolvendo os dois valores. A primeira versão usa global maior, menor:

maior = None
menor = None

def registrar(valor):
    global maior, menor
    if maior is None or valor > maior:
        maior = valor
    if menor is None or valor < menor:
        menor = valor

for v in (512, 700, 300, 450):
    registrar(v)
print("menor", menor, "maior", maior)

A saída é menor 300 maior 700. A segunda versão recebe o estado atual por parâmetro e devolve o novo:

def atualizar(valor, menor, maior):
    if menor is None or valor < menor:
        menor = valor
    if maior is None or valor > maior:
        maior = valor
    return menor, maior

menor = None
maior = None
for v in (512, 700, 300, 450):
    menor, maior = atualizar(v, menor, maior)
print("menor", menor, "maior", maior)

A saída é a mesma. A segunda versão tem uma vantagem, que é poder ser testada com atualizar(5, None, None) sem preparar nenhuma variável do arquivo. Para melhorar, faça uma terceira versão que também conte quantos valores foram registrados.

Perguntas frequentes

O que é escopo?

É a região do programa em que um nome é válido. Em Python, as funções criam escopos próprios. O arquivo inteiro forma o escopo global.

Preciso de global para ler uma variável de fora?

Não. Só para reatribuí-la. Ler é livre, e métodos que alteram o objeto no lugar, como append, também dispensam.

Qual a diferença entre global e nonlocal?

O global aponta para um nome do arquivo. O nonlocal aponta para um nome da função externa mais próxima que o tem. Em funções não aninhadas, só o global faz sentido.

As variáveis do laço for são locais ao laço?

Não. Continuam existindo depois dele, com o valor da última volta. Em funções, são locais à função.

Por que o Python decide que a variável é local antes de rodar?

Porque lê o corpo inteiro da função ao compilá-la, e qualquer atribuição ao nome o marca como local. É por isso que um print(x) antes de x = 2 falha.

Uso global na ESP32?

Com moderação. É comum para o estado de callbacks, para constantes e para objetos de hardware. Para o resto, parâmetros e return deixam o programa mais fácil de ler e de testar.

Para continuar

Releia os artigos sobre funções, parâmetros e argumentos e return, que formam a base deste. Os desafios Função Dobro e Calculadora com Funções mostram o caminho preferido: valores entram por parâmetro e saem por return, sem variável global. A trilha Lógica com Python reúne todos.

O próximo artigo trata da recursividade: a função que chama a si mesma, como ela se encerra, por que o limite de recursão é menor no MicroPython e quando um laço resolve melhor.

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre