Escopo e Namespace em Python

Em Python, escopo é o contexto onde um nome pode ser usado. Ele define a região do código, o tempo de vida e os limites de acesso desses nomes.

Durante a execução do seu programa, um ou mais escopos estarão ativos. Isso determina quais nomes estão visíveis naquele momento e quais resultarão em um NameError se você tentar acessá-los.

Os nomes definidos dentro de um escopo são armazenados em um objeto chamado namespace. Ele atua como um dicionário, onde a chave é o nome (ou rótulo) de um objeto e o valor é o objeto referenciado.

Neste artigo, vamos explorar não apenas o que são escopo e namespace, mas também vários outros temas relacionados. Ao final, você terá aprendido:

  • O que é escopo
  • O que é namespace
  • Os tipos de escopo: Local, Enclosing, Global e Built-in
  • A regra LEGB: a ordem de busca por nomes
  • Como usar as palavras-chave global e nonlocal de forma consciente
  • Como usar funções como globals(), locals(), vars() e dir() para inspecionar e acessar namespaces

Em vídeo

Eu falo sobre escopo e namespace no Python (tudo o que falo neste artigo) em dois vídeos no meu canal do Youtube. Caso prefira, assista abaixo:


O que é escopo?

Quando você cria um nome em seu código, como uma variável, uma função ou uma classe, ele só pode ser usado dentro de um certo contexto. Esse contexto é o que chamamos de escopo.

Em termos práticos, escopo é a região do seu código onde um nome está diretamente acessível. Ou seja, é onde o Python vai “procurar” por aquele nome quando você tenta utilizá-lo. Se você conseguir acessar o nome solicitado, falamos que ele está no escopo, do contrário ele estará fora do escopo.

Nota:: sempre que eu usar a palavra “nome”, estou me referindo a identificadores como variáveis, classes, funções, módulos ou qualquer coisa que pode receber um nome em Python.

Vamos para um exemplo (sempre leia os comentários de código):

x = 10  # Variável 'x' no escopo global

def mostrar():
    print(x)  # Acessa 'x' do escopo global

mostrar()

Nesse código, a variável x foi definida no escopo global, fora de qualquer função. Quando print(x) é chamado dentro da função mostrar(), o Python primeiramente busca x no escopo local da função. Como não o encontra lá, ele “sobe” para o escopo global, onde x está disponível.

Mas onde o Python guarda esse nome x com o valor 10?

É nesse ponto que os namespaces entram em cena: todo escopo possui seu próprio “espaço de nomes”, um local onde os nomes e seus respectivos objetos são armazenados. Vamos explorar isso em detalhes a seguir.


O que é namespace?

Um namespace é, essencialmente, uma estrutura que mapeia nomes a objetos. Você pode pensar nele como um dicionário onde cada chave é o nome que você define (como o nome de uma variável, função ou classe) e o valor é o objeto correspondente no seu código.

Sempre que você cria um nome em Python, essa associação é guardada dentro de um namespace. Algumas das formas mais comuns de criar nomes incluem:

  • Atribuição: variavel = valor
  • Importação: import modulo ou from modulo import objeto
  • Definição de funções: def minha_funcao(): ...
  • Argumentos de funções: def outra_funcao(arg1, arg2): ...
  • Definição de classes: class MinhaClasse: ...

Nota: existem diferenças entre operações de atribuição (criar ou modificar um valor) e operações de acesso (apenas ler um valor). Vamos falar sobre isso nesse artigo na seção “global e nonlocal - alterando nomes fora do escopo”.

Todos esses exemplos resultam na criação de nomes dentro do namespace ativo no momento da sua definição.

Cada namespace está diretamente ligado a um escopo, que determina onde e quando aquele nome estará disponível durante a execução do seu código.

Embora você possa inspecionar namespaces usando funções como globals() e locals() (que retornam representações em dicionário), isso é mais comum para introspecção de código ou fins didáticos do que para o uso diário.

Existem diferentes tipos de namespaces em Python, cada um com sua finalidade:

  • Global: Cada módulo Python possui um namespace global, que armazena os nomes definidos diretamente na sua raiz, fora de funções ou classes.
  • Local: Cada vez que uma função é chamada, um namespace local é criado para ela. Ele existe apenas enquanto a função está em execução e contém as variáveis e argumentos definidos dentro dela.
  • Built-in: Este namespace contém os nomes de todas as funções e exceções nativas do Python, como print(), len(), str(), etc. Ele é carregado automaticamente.
  • Enclosing (Não-local): Quando uma função é definida dentro de outra, a função interna pode acessar os nomes do namespace da função externa. Este atua como um escopo “intermediário” entre o local e o global.
  • Classes: O corpo de uma classe também forma seu próprio namespace, onde os atributos e métodos da classe são definidos. É por isso que você acessa membros da classe usando a notação de ponto (objeto.atributo).

É importante notar que os namespaces de funções (Local e Enclosing) são criados dinamicamente no momento da execução. Quando uma função é chamada, o interpretador Python gera um Frame de Execução (ou Stack Frame) que encapsula as variáveis locais, parâmetros e outras informações necessárias para aquela chamada específica. A função locals() pode ser usada dentro de uma função para acessar seu namespace local.

Uma característica fundamental é que todos os namespaces são independentes entre si. Por exemplo, você pode ter uma função chamada processar() em dois módulos diferentes (modulo1.py e modulo2.py). Não haverá conflito, pois cada uma reside em seu próprio namespace. Para acessá-las, basta prefixar com o nome do módulo: modulo1.processar() e modulo2.processar().


globals() e locals() para inspeção de namespaces

As funções globals() e locals() são ferramentas valiosas para inspecionar namespaces em tempo de execução:

  • globals(): Retorna um dicionário que representa o namespace global do módulo atual. Isso inclui todos os nomes definidos na raiz do arquivo.
  • locals(): Retorna um dicionário com os nomes definidos no escopo local onde a função está sendo executada. Importante: ela só inclui nomes que já foram definidos antes da sua chamada, então geralmente é melhor chamá-la no final do bloco.

Vejamos um exemplo prático:

# Escopo global

def show_namespace() -> None:
    # Escopo local
    module_namespace = globals()
    print("Conteúdo de globals():", module_namespace)

    # Note que 'function_namespace' não aparecerá no locals() se chamado antes dela
    function_namespace = locals()
    print("Conteúdo de locals():", function_namespace)


if __name__ == "__main__":
    show_namespace()

A saída de globals() será algo parecido com:

{
    '__name__': '__main__',
    '__doc__': None,
    # ... outras chaves padrão do módulo
    '__builtins__': <module 'builtins' (built-in)>,
    'show_namespace': <function show_namespace at 0x...> # Nossa função
}

Já a saída de locals() mostrará:

{
    'module_namespace': {...} # O dicionário retornado por globals()
}

Alguns pontos a destacar nessa saída:

  • __name__: Indica o nome do módulo. Se for o script principal, será __main__.
  • __builtins__: Referência ao namespace com as funções nativas do Python.
  • show_namespace: O nome da nossa função, definida no escopo global.

vars() e dir() - Outras formas de inspecionar

Além de globals() e locals(), vars() e dir() também permitem inspecionar nomes, mas com algumas diferenças importantes:

  • vars(): Retorna o atributo __dict__ de um objeto, que é onde seus atributos são armazenados. Se chamada sem argumentos, vars() se comporta exatamente como locals(), retornando o namespace local.
  • dir(): Sem argumentos, dir() lista todos os nomes disponíveis no escopo atual. Com um objeto como argumento, tenta listar todos os nomes acessíveis nele (como métodos e atributos). Note que dir() retorna apenas os nomes, não os objetos ou seus valores.

Vamos ver com um exemplo:

def ver_namespace_local():
    var_local = "variável local"

    print("\nDENTRO DA FUNÇÃO (ESCOPO LOCAL)")
    print("Saída de vars():", vars())
    print("Saída de dir():", dir())


print("FORA DA FUNÇÃO (ESCOPO GLOBAL)")
print("Saída de vars():", vars())
print("Saída de dir():", dir())

ver_namespace_local()

Saída de exemplo:

# FORA DA FUNÇÃO (ESCOPO GLOBAL)
# Saída de vars():
{
    # ... omitidos outros resultados globais
    'ver_namespace_local': <function ver_namespace_local at 0x...>
}
# Saída de dir():
[
    '__annotations__', '__builtins__', '__cached__', '__doc__',
    '__file__', '__loader__', '__name__', '__package__', '__spec__',
    'ver_namespace_local' # Nossa função global
]

# DENTRO DA FUNÇÃO (ESCOPO LOCAL)
# Saída de vars():
{
    'var_local': 'variável local'
}
# Saída de dir():
['var_local']

Como pode ver, quando usadas sem argumentos, vars() e dir() se assemelham a locals() e globals() no que diz respeito ao escopo atual. A grande diferença é que vars() e dir() são mais versáteis, pois podem receber um objeto como argumento, permitindo inspecionar namespaces de módulos importados, instâncias de classe e outros objetos.


Regra LEGB - Local, Enclosing, Global e Built-In

Em Python, é bem comum ter um escopo dentro do outro, pense em funções dentro de módulos, ou até mesmo funções aninhadas dentro de outras funções.

Quando isso acontece e você tenta acessar um nome (como uma variável ou função), o interpretador precisa de uma ordem clara para encontrá-lo, dependendo do ponto em que você está no código.

Essa ordem é definida pela regra LEGB. Sempre que você referencia um nome, seja para leitura, escrita ou execução (tipo x ou print()), o Python o busca sequencialmente, do escopo mais interno para o mais externo:

  • Local (L): Primeiro, o Python procura no escopo da função atual onde o nome está sendo referenciado. Este é o ambiente mais imediato.
  • Enclosing (E) / Não-Local: Se o nome não for encontrado localmente, a busca avança para o escopo das funções que envolvem a função atual (se houver). Pense nisso como o escopo “da função de fora”.
  • Global (G): Caso o nome ainda não seja encontrado, o Python então procura no escopo do módulo atual. Este é o nível superior do seu arquivo Python.
  • Built-in (B): Por último, a busca chega ao escopo built-in, que contém todos os nomes nativos do Python, como funções (len(), print()) e exceções (NameError).

Se o nome não for encontrado em nenhum desses escopos, o Python levanta uma exceção NameError, indicando que o nome não foi definido ou não está acessível no contexto atual.

Para visualizar como esses escopos se aninham, imagine a seguinte representação:

 ┌─────────────────────┐
 │ ┌───────────────┐   │
 │ │ ┌─────────┐   │   │
 │ │ │ ┌───┐   │   │   │
 │ │ │ │ L→│ → │ → │ → │ # Local (L): Onde você está agora, o mais interno
 │ │ │ └───┘   │   │   │
 │ │ │       E→│ → │ → │ # Enclosing (E): A função que envolve a sua função
 │ │ └─────────┘   │   │
 │ │             G→│ → │ # Global (G): O módulo inteiro do seu arquivo
 │ └───────────────┘   │
 │                  B→✘│ # Built-in (B): Mais externo, tudo do Python
 └─────────────────────┘

Se preferir, preparei uma imagem também para te ajudar a entender melhor.

Diagrama mostrando a regra LEGB do Python

A seguir, vamos ver exemplos de código para tornar cada um desses escopos cristalino.


A regra LEGB em ação

Para entender a regra LEGB na prática, vamos usar um código simples e observar como o Python busca os nomes em cada escopo. Usei bastante os comentátios do código para detalhar melhor o que está acontecendo.

# Escopo do módulo: Global (G)
var_global = "Estou no escopo global!"

def funcao_externa() -> None:
    # Escopo da função: Local (L) para esta função
    var_local = "Estou no escopo local!"

    # Busca de 'var_local':
    # O Python encontra 'var_local' no escopo Local (L).
    print(var_local)

    # Busca de 'var_global':
    # Não encontra 'var_global' no Local (L), então busca no Global (G).
    print(var_global)

    # Busca de 'print':
    # Não encontra 'print' em L ou G, então busca no Built-in (B).
    print(print) # Imprime a representação da própria função print


if __name__ == "__main__":
    funcao_externa()

Analisando o fluxo de busca de nomes nesse exemplo, o Python segue a regra LEGB (sempre do mais interno ao mais externo):

  • var_local: Encontrado diretamente no escopo Local da funcao_externa. Trajeto: L.
  • var_global: Não encontrado em L, a busca sobe para o escopo Global. Trajeto: L → G.
  • print: Não encontrado em L nem em G, a busca atinge o escopo Built-in. Trajeto: L → G → B.

É fundamental entender que essa busca é sempre unidirecional: de dentro para fora. Escopos mais internos conseguem “enxergar” os nomes definidos nos escopos mais externos (que os contêm), mas o contrário não é verdadeiro.

Veja um exemplo clássico de NameError que prova isso:

def funcao_interna():
    mensagem = "Olá do escopo local!"

# Erro! 'mensagem' só existe dentro de 'funcao_interna'
print(mensagem)
# Saída esperada: NameError: name 'mensagem' is not defined

A mensagem de erro NameError: name 'mensagem' is not defined ocorre porque, no escopo global, o Python não consegue “descer” para o escopo local de funcao_interna para encontrar mensagem.

Em resumo: a regra LEGB é uma escada de subida. Você só vê os andares acima ou o seu próprio. Nunca consegue ver o que está nos andares abaixo do seu.


Keywords não seguem a LEGB!

É importante diferenciar nomes de keywords (palavras-chave). Termos como def, if, for, while, return, True, False, None e import são partes da gramática do Python, não nomes.

Por serem palavras reservadas, elas não pertencem a nenhum namespace e, consequentemente, não seguem a regra LEGB. Tentar usá-las como variáveis resultará em um erro de sintaxe (SyntaxError) no momento da análise do código, antes mesmo da execução:

# Isso vai causar um SyntaxError!
# Esse código nem chega a rodar
def = 10

Se quiser ver a lista completa de palavras-chave reservadas, execute o comando abaixo no seu terminal Python:

python -c "help('keywords')"

Isso mostrará a lista das keywords do Python, como False, True, None, and, as, assert, break, class, etc. (Existem também as soft keywords, mas isso fica para outra conversa).


Enclosing - entenda o escopo aninhado

Enquanto os escopos Global, Local e Built-in costumam ser mais intuitivos, o escopo Enclosing gera mais dúvidas porque ele só aparece em um cenário específico: quando temos funções aninhadas, ou seja, uma função definida dentro de outra. Vamos focar nele agora.

Considere este código:

def funcao_externa():
    # 'var_enclosing' é local para 'funcao_externa'
    # e Enclosing para 'funcao_interna'
    var_enclosing = "Eu sou do escopo enclosing!"

    def funcao_interna():
        # 'var_local' está no escopo Local de 'funcao_interna'
        var_local = "Eu sou do escopo local!"

        # Acessando 'var_local' (L) e 'var_enclosing' (E)
        print(var_local, var_enclosing)

    # Chamamos a função interna para executá-la
    funcao_interna()

funcao_externa()
# Saída esperada: Eu sou do escopo local! Eu sou do escopo enclosing!

Como você pode ver na saída, a funcao_interna() consegue acessar tanto var_local (que está em seu escopo Local) quanto var_enclosing (que está no escopo Enclosing, da funcao_externa). Isso acontece exatamente por causa da regra LEGB: o Python busca os nomes de dentro para fora, encontrando var_enclosing no nível acima.

Por outro lado, a funcao_externa() não tem acesso direto a var_local, pois var_local reside em um escopo mais interno que o dela. Da mesma forma, o escopo global não consegue acessar nenhuma das variáveis definidas dentro de funcao_externa ou funcao_interna.


Call stack e o tempo de vida dos escopos

A razão para esse comportamento reside em como o Python gerencia a execução de funções utilizando a call stack (pilha de chamadas).

Sempre que uma função é chamada, o Python cria um frame de execução (ou stack frame) para ela. Esse frame é empilhado no topo da call stack, que funciona no esquema LIFO (Last-In, First-Out: o último que entra é o primeiro que sai). Apenas o frame no topo da pilha está ativo. Quando a função termina sua execução, seu frame é descartado da pilha, e o Python retorna o controle para o frame anterior. É por isso que o escopo local de uma função só “existe” enquanto ela está em execução.

Exemplo da call stack do Python em execução

A imagem acima ilustra a call stack em ação. O ícone do Python indica a posição atual do interpretador. As setas vermelhas (--->) representam o fluxo de execução e a criação/remoção de frames na pilha. As setas amarelas () mostram a direção de busca de nomes de acordo com a regra LEGB (do escopo mais interno para o mais externo).

Observe o fluxo na imagem:

  1. A execução inicia no mod.py (escopo Global).
  2. Ao chamar funcao_externa(), um novo frame é empilhado. O interpretador se move para dentro dela.
  3. Dentro de funcao_externa(), ao chamar funcao_interna(), outro frame é empilhado, e o interpretador se move para lá.
  4. Quando funcao_interna() termina, seu frame é desempilhado, e o controle retorna para funcao_externa().
  5. Finalmente, funcao_externa() termina, seu frame é desempilhado, e a execução retorna ao mod.py (escopo global), concluindo o processo.

Esse mecanismo é fundamental para a organização e o isolamento do código:

  • Você consegue acessar nomes definidos em escopos mais externos (Globais, Enclosing) a partir de dentro de uma função.
  • Mas não consegue acessar nomes definidos dentro de funções estando fora delas, porque o escopo local de uma função deixa de existir (é descartado) assim que ela termina de executar.

Para um aprofundamento sobre a call stack e funções, especialmente em cenários como recursão, recomendo este material:

Agora que entendemos o Enclosing e o que acontece por baixo dos panos, podemos continuar.


global e nonlocal - Alterando nomes fora do escopo atual

Nas seções anteriores, focamos em como os nomes são acessados (lidos) de um escopo em outro, um processo que tende a ser mais direto.

No entanto, a tentativa de alterar um nome que não foi definido no escopo atual gera uma ambiguidade para o interpretador. Como ele saberia se você quer criar um novo nome local (com o mesmo rótulo) ou modificar o nome existente em um escopo externo? Essa é a questão.

Essa ambiguidade surge justamente pela flexibilidade que o Python oferece: a capacidade de ter nomes iguais em escopos diferentes sem que um afete o outro, a menos que você explicitamente peça.

Mas… antes de mergulharmos nas soluções, uma pausa para as boas práticas.


Devo alterar nomes fora de seu escopo imediato?

A principal função do escopo e do namespace é proteger nomes de alterações acidentais e garantir o isolamento do código. Fazer alterações intencionais em nomes que residem fora do escopo imediato vai, em certa medida, contra essa ideia central.

Vou listar alguns problemas que essa prática pode gerar (e a lista é bem maior):

  • Dificulta o Debug: Rastrear a origem de um bug se torna um pesadelo quando variáveis são alteradas de forma “mágica” em diferentes partes do código.
  • Dificulta Testes: Funções que dependem ou alteram o estado global são mais complexas de testar isoladamente, exigindo um setup e cleanup maiores.
  • Reduz a Legibilidade e Manutenção: O código fica menos intuitivo, exigindo que o leitor “pule” entre escopos para entender o fluxo de dados.
  • Aumenta o Acoplamento: Módulos e funções se tornam mais interdependentes, tornando o sistema mais rígido e difícil de refatorar.
  • Problemas em Concorrência: Em ambientes multi-thread ou assíncronos, a alteração de estado global pode levar a race conditions e bugs extremamente difíceis de diagnosticar.
  • Contraria Paradigmas Comuns: Vai contra princípios de paradigmas como programação funcional (que preza imutabilidade) e orientação a objetos (que encapsula estado).

Se você se encontrar na situação de precisar alterar o valor de uma variável fora do seu escopo imediato, pare e reavalie a sua solução. Quase sempre há uma forma mais elegante e segura de resolver o problema, como passar os valores via argumentos ou retornar novos valores.

Ok, com essa ressalva importante em mente, agora sim vamos entender como global e nonlocal funcionam para alterar variáveis fora do seu escopo local.


global - alterando nomes no escopo global

Vamos analisar o comportamento padrão quando tentamos alterar uma variável global dentro de uma função. Acompanhe o código e o erro que ele gera:

# Escopo global (G)
variavel = "global"

def funcao():
    # Tentativa de usar `variavel` (G)
    print(variavel) # <-- ISSO VAI GERAR O ERRO

    # Criei um novo nome `variavel` no escopo LOCAL (L)
    # Isso fez o nome `variavel` deixar de existir no print acima
    variavel = "local" # <-- ESSE É O MOTIVO DO ERRO

    # Agora, estamos tentando usar a `variavel` LOCAL
    print(variavel)

funcao() # <-- O interpretador não passa daqui
print(variavel)
# A `variavel` global original permanece inalterada

Ao executar funcao(), você receberá um UnboundLocalError:

UnboundLocalError: cannot access local variable 'variavel'
where it is not associated with a value

O interpretador Python é inteligente: ao ver a linha variavel = "local" dentro da função, ele assume que variavel será uma variável local para funcao(). Portanto, quando print(variavel) é chamado antes dessa atribuição local, Python busca por variavel no escopo local, encontra uma referência de atribuição futura, mas percebe que ela ainda não tem um valor associado dentro daquele escopo local. Isso causa o UnboundLocalError.

Para informar ao Python que você deseja modificar a variável variavel que reside no escopo global, utilizamos a palavra-chave global:

variavel = "global"

def funcao():
    # 'global variavel' informa ao interpretador
    # que estamos referenciando e modificando a variável global.
    global variavel

    # Agora, podemos usar a variável global ANTES de alterá-la
    print(variavel) # Saída: global

    # Esta atribuição agora modifica a variável global
    variavel = "local"
    print(variavel) # Saída: local

funcao()
print(variavel) # Saída: local (o valor global foi alterado com sucesso)

Com global variavel, a primeira chamada a print(variavel) acessa o valor “global”. Em seguida, a linha variavel = "local" realmente altera a variavel do escopo global.

Importante: A declaração global deve ser feita para cada variável global que você pretende alterar dentro de cada função onde essa alteração ocorrerá.

Finalmente, vale ressaltar que global só funciona para nomes no escopo global. Se você precisar alterar um nome em um escopo Enclosing (não-local), você precisará usar outra palavra-chave do Python: nonlocal.


nonlocal: alterando nomes do escopo enclosing

A palavra-chave nonlocal tem uma função similar a global, mas atua no escopo Enclosing (o E da regra LEGB), ou seja, em variáveis de funções externas que envolvem a função atual, mas que não são o escopo global.

Isso é particularmente útil em cenários onde uma função interna precisa modificar uma variável definida na função que a contém.

Veja o exemplo a seguir com apenas dois níveis de aninhamento:

def soma_mais_um():
    # 'numero' está no escopo Enclosing para 'incrementa'
    numero = 0

    def incrementa():
        # 'nonlocal numero' informa que queremos modificar
        # o 'numero' do escopo Enclosing (soma_mais_um)
        nonlocal numero
        numero += 1
        print(f"Número atual (interno): {numero}")

    # Até aqui, nada alterado
    print(f"Número inicial (externo): {numero}")

    incrementa() # A alteração ocorre aqui
    print(f"Número final (externo): {numero}")

soma_mais_um()
# Saída esperada:
# Número inicial (externo): 0
# Número atual (interno): 1
# Número final (externo): 1

Neste exemplo, a função incrementa() consegue modificar a variável numero que pertence à soma_mais_um(), no seu escopo Enclosing. Se nonlocal numero não fosse usado, incrementa() criaria sua própria variável local numero, sem afetar a de fora.

Cuidado com a complexidade: Embora nonlocal seja uma ferramenta poderosa e frequentemente usada em padrões como closures e decorators, o aninhamento excessivo de funções e o uso indiscriminado de nonlocal podem levar a um código difícil de ler e depurar. Como já mencionado na seção de boas práticas, sempre reavalie se há uma forma mais clara de estruturar seu código.


Concluindo - agora você passou de nível 😁

E assim chegamos ao fim do nosso texto sobre os conceitos de escopo e namespace em Python. Embora esse assunto possa parecer muito abstrato, ele acaba sendo um dos pontos principais para compreender como o Python funciona. Na verdade, não só Python! Muitas outras linguagens funcionam de maneira muito similar. Você vai levar esse conhecimento para todas elas.

Revisamos que:

  • Um escopo define o local do código onde um nome estará visível e acessível.
  • Um namespace é a estrutura que armazena essas associações entre nomes e objetos.
  • Escopo e Namespace são dois assuntos conectados em Python
  • A regra LEGB (Local, Enclosing, Global, Built-in) é a ordem pela qual o Python busca por nomes, sempre de dentro para fora.
  • Vimos como as funções globals(), locals(), vars() e dir() podem nos ajudar a inspecionar esses “dicionários” de nomes em tempo real.
  • E, finalmente, aprendemos sobre as palavras-chave global e nonlocal, que nos permitem, quando necessário e com muita cautela, alterar nomes em escopos externos ao imediato.

Dominar esses conceitos não é apenas sobre “saber o que acontece”, mas sobre entender por que seu código se comporta como se comporta, evitar erros comuns como o UnboundLocalError, e escrever um código mais robusto e previsível.

Lembre-se sempre da lição sobre as boas práticas: alterar nomes fora do seu escopo imediato deve ser a exceção, não a regra. Priorize a clareza, o baixo acoplamento e a previsibilidade do seu código.

Com essa base sólida sobre escopo e namespace, você está pronto para mergulhar em tópicos mais avançados do Python, como closures e decorators, que dependem diretamente desse entendimento. Continue praticando e experimentando!

Comentários

No seu e-mail

Newsletter

Junte-se a centenas de outros desenvolvedores e receba dicas e conteúdo técnico diretamente na sua caixa de entrada. Sem SPAM ou publicidade. Apenas conteúdo de qualidade.