
Passo 1 de 8
Onde cada nome existe
Reconheça em que contexto os nomes de um programa são definidos: no corpo da função, no nível superior do arquivo ou entre os recursos embutidos do Python.
Trilha de aprendizado · Nível 4 · Tutorial 2
Preveja quais nomes e alterações são visíveis dentro e fora de uma função e reduza a dependência de variáveis globais.
Onde cada nome existe
Reconheça em que contexto os nomes de um programa são definidos: no corpo da função, no nível superior do arquivo ou entre os recursos embutidos do Python. 2 min
Qual nome a função usa
Use a prioridade local, global do arquivo e embutido para prever qual valor será encontrado quando nomes coincidem. 2 min
O estado local em cada chamada
Entenda por que os nomes locais são criados novamente a cada chamada e preveja o resultado de chamadas sucessivas. 2 min
Por que ocorre UnboundLocalError
Reconheça quando uma função tenta ler um nome local antes de atribuir um valor a ele e escolha correções que garantam um valor em todos os caminhos necessários. 3 min
Reatribuir um parâmetro ou alterar o objeto
Diferencie a reatribuição de um parâmetro da alteração do objeto mutável recebido pela função. 3 min
O que a declaração global permite
Use global para reatribuir um nome do arquivo e reconheça quando uma função passa a depender do histórico de chamadas. 2 min
Trocar estado global por entradas e retornos
Transforme uma função que altera um contador global em uma função que recebe o estado atual, calcula o próximo valor e o devolve ao chamador. 3 min
Aplicação final: tornar os efeitos previsíveis
Refatore um contador de tarefas para substituir estado global por parâmetro e retorno, preservando a mutação intencional de uma lista recebida. 3 min

Passo 1 de 8
Reconheça em que contexto os nomes de um programa são definidos: no corpo da função, no nível superior do arquivo ou entre os recursos embutidos do Python.
Escopo é o contexto em que um nome pode ser consultado. Nos exemplos deste tutorial, com funções definidas diretamente no nível superior de um arquivo, observe três categorias:
len e print, que você pode usar sem defini-los.O corpo da função forma o contexto local; o restante do arquivo contém os nomes globais desse arquivo; e o Python disponibiliza nomes embutidos.

Parâmetros e atribuições no corpo ficam na área local; definições no nível superior pertencem ao arquivo; recursos embutidos são fornecidos pelo Python.
Observe onde cada nome é definido ou de onde ele vem.
prefixo = "Itens"
def resumir(nomes):
quantidade = len(nomes)
mensagem = f"{prefixo}: {quantidade}"
print(mensagem)
return quantidade
resultado = resumir(["caderno", "lápis"])No nível superior do arquivo são definidos prefixo, resumir e resultado. Dentro da função, o parâmetro nomes e os alvos de atribuição quantidade e mensagem são locais. Já len e print são nomes embutidos fornecidos pelo Python.
Dica
Pergunte: “Esse nome foi definido no nível superior do arquivo, é um parâmetro ou recebeu um valor dentro da função, ou já é fornecido pelo Python?”
Com base no código anterior, associe cada nome à sua categoria.
Toque em um item e depois no par correspondente.

Passo 2 de 8
Use a prioridade local, global do arquivo e embutido para prever qual valor será encontrado quando nomes coincidem.
Nas funções não aninhadas deste tutorial, o Python procura um nome nesta ordem: local → global do arquivo → embutido. A busca termina na primeira associação encontrada.
Um parâmetro ou outro nome local pode ocultar um global de mesmo nome. Se não houver associação local, a função pode consultar o global. Se também não houver global, nomes embutidos como print e len continuam disponíveis.

A busca segue do local para o global e depois para os embutidos, parando assim que encontra o nome.
Observe os valores exibidos dentro e fora da função.
tema = "global"
def mostrar(tema):
origem = "local"
print(tema, origem)
mostrar("argumento")
print(tema)
# Saída:
# argumento local
# globalDentro de mostrar, o parâmetro local tema é encontrado antes do global de mesmo nome. Fora da função, tema continua associado a "global".
O nome print não foi definido local nem globalmente, então a busca chega à função embutida.
A associação local não substitui a associação global de mesmo nome.
cor = "azul"
def escolher_cor():
cor = "verde"
return cor
print(escolher_cor()) # verde
print(cor) # azulNeste exemplo, a associação global chamada len é encontrada antes do recurso embutido de mesmo nome.
len = 4
def mostrar_limite():
return len
print(mostrar_limite()) # 4Dica
Evite usar nomes como len e print para suas variáveis. Nomes como limite, quantidade e mensagem preservam o acesso aos recursos embutidos e deixam a intenção mais clara.
Considere o código:
rotulo = "fora"
def exibir(rotulo):
local = "dentro"
print(rotulo, local)
exibir("argumento")
print(rotulo)Quais linhas serão exibidas, nessa ordem?

Passo 3 de 8
Entenda por que os nomes locais são criados novamente a cada chamada e preveja o resultado de chamadas sucessivas.
Cada chamada de uma função estabelece suas próprias associações locais. Os parâmetros recebem os objetos enviados como argumentos naquela chamada, e as atribuições do corpo criam valores locais para essa execução.
Por isso, um contador inicializado dentro da função começa novamente do valor definido no corpo. A chamada seguinte não continua automaticamente o contador da chamada anterior.
Em cada chamada, etiqueta recebe o argumento atual e contador começa em 0.
def registrar(etiqueta):
contador = 0
contador = contador + 1
return f"{etiqueta}: {contador}"
primeiro = registrar("A")
segundo = registrar("B")
print(primeiro)
print(segundo)
Cada quadro representa uma chamada. A segunda cria suas próprias associações locais, em vez de reutilizar as da primeira.
Dica
O valor retornado pode ser guardado pelo chamador, como em primeiro e segundo. Isso não transforma contador em um nome global: esse nome continua sendo local a cada chamada.
Observe que passos é inicializado dentro da função.
def contar(categoria):
passos = 0
passos = passos + 1
return passos
resultado_a = contar("estudo")
resultado_b = contar("lazer")
print(resultado_a, resultado_b)A única linha exibida pelo código é ____.

Passo 4 de 8
Reconheça quando uma função tenta ler um nome local antes de atribuir um valor a ele e escolha correções que garantam um valor em todos os caminhos necessários.
Se o corpo de uma função atribui a um nome, esse nome é considerado local em toda a função nos exemplos deste tutorial. Isso vale até para as linhas anteriores à atribuição.
Ao tentar ler esse nome antes que ele receba um valor na chamada atual, Python gera UnboundLocalError. Um nome global com o mesmo texto não é usado como alternativa: a busca já determinou que o nome é local.
A primeira instrução do corpo tenta ler saldo. Porém, a atribuição posterior faz saldo ser local em toda a função.
saldo = 100
def ajustar():
print(saldo) # tenta ler o saldo local
saldo = saldo + 10
return saldo
ajustar() # UnboundLocalErrorO nome é classificado como local por causa da atribuição presente no corpo. Durante a execução, a leitura chega antes de esse espaço local receber um valor.

A presença do global saldo = 100 não preenche o saldo local ainda vazio.
Uma variável local precisa receber um valor antes da leitura em cada caminho que possa chegar a essa leitura. No código abaixo, valor é atribuído quando ativo é verdadeiro, mas permanece sem valor quando o argumento é False.
A falha acontece em print(valor) na chamada com False.
limite = 10
def escolher(ativo):
if ativo:
valor = limite + 5
print(valor)
return valor
escolher(False) # UnboundLocalErrorA primeira função garante uma atribuição antes da condição. A segunda usa nomes diferentes para o global consultado e para o resultado local.
limite = 10
def escolher(ativo):
valor = limite
if ativo:
valor = limite + 5
return valor
desconto = 10
def calcular_preco(preco):
desconto_aplicado = desconto + 5
return preco - desconto_aplicadoAtenção
Mover um print ou um return para outra linha só corrige o problema se todos os caminhos que chegam à nova posição já tiverem atribuído um valor ao nome local.
Considere a chamada preparar(False). Qual operação falha primeiro, e por quê?
base = 20
def preparar(aplicar):
print(base)
if aplicar:
base = 25
return base
preparar(False)A intenção é devolver valor quando adicional for falso e devolver valor + taxa quando for verdadeiro. Qual alteração corrige a função para as duas situações?
taxa = 2
def calcular(valor, adicional):
if adicional:
resultado = valor + taxa
print(resultado)
return resultado
Passo 5 de 8
Diferencie a reatribuição de um parâmetro da alteração do objeto mutável recebido pela função.
Um parâmetro é um nome local associado ao objeto fornecido como argumento. Se o argumento for uma lista, a função não cria uma cópia automática.
Por isso, duas operações têm efeitos diferentes:
itens = ["novo"] faz o parâmetro apontar para outra lista. O nome do chamador continua apontando para a lista original.itens.append("novo") ou itens[0] = "novo" modifica a lista compartilhada. O chamador observa a alteração.Compare os caminhos das referências antes e depois de cada operação.

Reatribuir muda a seta do nome local; mutar altera o objeto apontado pelas setas compartilhadas.
Execute o código no seu ambiente e compare as duas listas exibidas.
def substituir(itens):
itens = ["novo"]
return itens
def acrescentar(itens):
itens.append("novo")
primeira = ["a", "b"]
resultado = substituir(primeira)
print(primeira) # ['a', 'b']
print(resultado) # ['novo']
segunda = ["a", "b"]
retorno = acrescentar(segunda)
print(segunda) # ['a', 'b', 'novo']
print(retorno) # NoneEm substituir, a reatribuição afeta somente o parâmetro local. O return permite obter a nova lista, mas não altera a lista original.
Em acrescentar, não há return explícito, mas a mutação permanece visível no chamador. Da mesma forma, adicionar um return depois de append não desfaria a alteração já feita.
Associe cada instrução executada dentro da função ao seu efeito.
Toque em um item e depois no par correspondente.
Antes de executar, preveja as duas linhas produzidas pelos print.
def atualizar(registros):
registros[0] = "feito"
registros = ["interno"]
registros.append("extra")
return registros
tarefas = ["pendente", "revisar"]
resultado = atualizar(tarefas)
print(tarefas)
print(resultado)Quais valores serão exibidos para tarefas e resultado? Justifique usando as referências antes e depois da reatribuição do parâmetro.
Escreva pelo menos 60 caracteres (0/60).

Passo 6 de 8
Use global para reatribuir um nome do arquivo e reconheça quando uma função passa a depender do histórico de chamadas.
Dentro de uma função, global contador indica que o nome contador se refere ao nome definido no nível superior do arquivo. Isso permite reatribuir esse nome, em vez de criar uma associação local.
A declaração deve aparecer antes das leituras e atribuições a esse nome no corpo da função.
Execute o código e observe que as duas chamadas atualizam o mesmo nome global.
contador = 0
def registrar_chamada():
global contador
contador = contador + 1
return contador
print(registrar_chamada()) # 1
print(registrar_chamada()) # 2
print(contador) # 2Um contador local inicializado no corpo recomeça em cada chamada. Já o contador declarado como global referencia uma única associação compartilhada pelas chamadas feitas naquele arquivo. Por isso, cada atualização global parte do estado deixado anteriormente.
Compare as referências: no modelo local, cada chamada possui seu próprio contador; no global, todas chegam ao mesmo contador externo.

À esquerda, estados locais independentes. À direita, um estado global compartilhado e atualizado em sequência.
Apenas consultar um nome global não exige global. Também não é necessário declarar global para modificar um objeto mutável encontrado por esse nome, desde que o próprio nome não seja reatribuído.
No exemplo, taxa é somente lido e a lista encontrada por historico é modificada. Nenhum dos dois nomes recebe uma nova associação dentro das funções.
taxa = 2
historico = []
def calcular(valor):
return valor * taxa
def registrar(nome):
historico.append(nome)
print(calcular(5)) # 10
registrar("Ana")
print(historico) # ['Ana']
# Estas reatribuições exigiriam global nas respectivas funções:
# taxa = 3
# historico = []Atenção
Uma função que lê ou reatribui estado global pode produzir resultados diferentes com os mesmos argumentos, dependendo do valor anterior e da ordem das chamadas. A mutação de um objeto global também deixa um efeito compartilhado, mesmo sem a declaração global.
Considere que todos os nomes citados já foram definidos no nível superior do arquivo. Em qual corpo de função a declaração global é necessária?
Se um contador global começa em 0 e uma função com global contador soma 1 a cada chamada, a segunda chamada parte do valor deixado pela primeira.

Passo 7 de 8
Transforme uma função que altera um contador global em uma função que recebe o estado atual, calcula o próximo valor e o devolve ao chamador.
Nesta versão, vender lê o valor anterior de estoque e reatribui esse mesmo nome global. Embora a chamada mostre apenas quantidade, o resultado também depende do estado deixado pelas chamadas anteriores.
Para tornar essa dependência explícita, o valor atual do estoque deve entrar como argumento, e o novo valor deve sair pelo return.
A função lê e reatribui estoque, mesmo que esse estado não apareça em sua lista de parâmetros.
estoque = 10
def vender(quantidade):
global estoque
estoque = estoque - quantidade
return estoque
print(vender(3)) # 7
print(vender(2)) # 5Atenção
Se apenas removermos global estoque, a expressão estoque - quantidade tentará ler um nome local antes de sua atribuição e causará UnboundLocalError. A refatoração precisa também receber o estado atual por parâmetro, devolvê-lo atualizado e guardar o retorno no código chamador.
Na versão refatorada, estoque_atual recebe o estado usado naquela chamada. A função calcula novo_estoque e o retorna, mas não decide onde esse resultado será guardado. Essa atribuição fica visível no chamador: estoque_a = vender(3, estoque_a).
Como não existe um único contador global compartilhado, a mesma função pode atualizar estoque_a e estoque_b de forma independente.
À esquerda, várias chamadas alcançam diretamente um único estado externo. À direita, cada valor entra na função como argumento e retorna ao respectivo nome no chamador.

No fluxo explícito, cada chamador fornece o estado atual e escolhe onde guardar o resultado retornado.
Copie e execute este código no seu ambiente. A definição completa de vender funciona com qualquer estoque fornecido pelo chamador.
def vender(quantidade, estoque_atual):
novo_estoque = estoque_atual - quantidade
return novo_estoque
estoque_a = 10
estoque_b = 20
estoque_a = vender(3, estoque_a)
estoque_b = vender(5, estoque_b)
print(estoque_a) # 7
print(estoque_b) # 15Complete o segundo parâmetro:
def vender(quantidade, ____):
novo_estoque = estoque_atual - quantidade
return novo_estoqueComplete o cálculo local:
def vender(quantidade, estoque_atual):
novo_estoque = ____
return novo_estoqueComplete o retorno:
def vender(quantidade, estoque_atual):
novo_estoque = estoque_atual - quantidade
return ____Complete a atualização explícita. Depois dessa instrução, estoque deve valer 8.
estoque = 12
estoque = ____
Passo 8 de 8
Refatore um contador de tarefas para substituir estado global por parâmetro e retorno, preservando a mutação intencional de uma lista recebida.
Ao analisar uma função, verifique: 1) onde cada nome foi definido; 2) se um nome local recebe valor antes de ser lido; 3) se a operação reatribui um nome ou modifica um objeto; 4) se o resultado depende de estado global.
No programa abaixo, tarefas, total_tarefas e registrar são nomes globais do arquivo. titulo e registros são parâmetros locais. A declaração global faz total_tarefas, dentro da função, referir-se ao nome global. Já print é um nome embutido.
A função produz dois efeitos diferentes: reatribui o contador global e modifica, por meio de registros, a mesma lista encontrada pelo nome tarefas no código chamador.
Copie este programa completo para um arquivo Python no seu computador. Antes de executá-lo, preveja as duas linhas finais.
total_tarefas = 0
tarefas = []
def registrar(titulo, registros):
global total_tarefas
registros.append(titulo)
total_tarefas = total_tarefas + 1
return total_tarefas
registrar("Estudar escopo", tarefas)
registrar("Revisar funções", tarefas)
print(total_tarefas)
print(tarefas)No seu editor, refatore o programa antes de consultar a solução de referência. Sua versão deve atender a todos estes critérios:
global.total_tarefas o retorno de cada chamada.registros.append(titulo), pois a alteração da lista é intencional.Execute a versão refatorada com as mesmas duas tarefas e confira as linhas exibidas.
Quais foram as duas linhas exibidas pela sua versão refatorada? Explique também por que tarefas continua mudando mesmo depois da remoção de global.
Escreva pelo menos 60 caracteres (0/60).
Compare esta solução com a sua. Aqui, total_atual e novo_total são nomes locais, assim como os parâmetros titulo e registros.
def registrar(titulo, registros, total_atual):
registros.append(titulo)
novo_total = total_atual + 1
return novo_total
total_tarefas = 0
tarefas = []
total_tarefas = registrar("Estudar escopo", tarefas, total_tarefas)
total_tarefas = registrar("Revisar funções", tarefas, total_tarefas)
print(total_tarefas)
print(tarefas)
# Saída esperada:
# 2
# ['Estudar escopo', 'Revisar funções']O contador percorre um fluxo explícito de entrada e retorno. A lista, por sua vez, é um objeto compartilhado que recebe novos elementos.

O retorno não modifica sozinho o contador do chamador: cada resultado precisa ser atribuído. A mutação da lista já permanece visível no objeto compartilhado.
Na primeira chamada, o contador entra como 0 e o retorno 1 é guardado em total_tarefas. Na segunda, esse 1 entra como argumento e o retorno 2 é guardado novamente.
Nas duas chamadas, registros permite alcançar a mesma lista. Cada append altera esse objeto. Portanto, retirar o estado global do contador não elimina a mutação intencional da lista — apenas torna explícito como o contador é atualizado.
Resumo
Use este resumo para prever o comportamento de outras funções.
Parabéns! Você concluiu: Controlar o escopo e o estado das funções
80 XP
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks