Namespaces, Pilha de Programa e Tratamento de Exceções em Python

7.1 Encapsulamento em Funções

Encapsular significa “esconder” a implementação de um bloco de código dentro de uma caixa‑preta. Em Python isso é feito com def. Quando chamamos a função, apenas os argumentos e o valor retornado são visíveis ao código que a invoca.

Reutilização de Código

Ao colocar um trecho usado várias vezes dentro de uma função, evitamos duplicação. Exemplo clássico:

def jump(t, x, y):
    t.penup()
    t.goto(x, y)
    t.pendown()

Qualquer parte do programa que precise “pular” a tartaruga pode chamar jump em vez de repetir as três linhas.

Modularidade (Decomposição Procedural)

Dividir um problema grande em funções menores permite desenvolver, testar e depurar cada parte isoladamente. No exemplo da carinha sorridente, jump e emoticon são módulos independentes.

Encapsulamento (Ocultação de Informações)

O código que usa jump não precisa saber que a tartaruga é levantada e depois recolocada; só precisa saber que o salto ocorre. Se a implementação mudar (por exemplo, usar t.setpos), emoticon continua funcionando.

Variáveis Locais

Variáveis criadas dentro de uma função são locais ao seu namespace de chamada. Elas desaparecem ao final da execução e não interferem em variáveis de mesmo nome fora da função.

def double(y):
    x = 2
    print(f"x = {x}, y = {y}")
    return x*y

Após double(3), x e y não existem no shell.

Ilustração de variáveis locais vs globais

Namespaces Associados a Chamadas de Função

Cada chamada cria um novo namespace. O interpretador procura nomes primeiro no namespace da chamada, depois no global e, por fim, no built‑ins.

Diagrama de namespaces em chamadas aninhadas

7.2 Namespaces Globais versus Locais

Variáveis definidas fora de funções (no módulo ou no shell) são globais. Dentro de funções são locais. O Python decide a origem de um nome na ordem: local → global → built‑ins.

Variáveis Globais

a = 0          # global no shell

Variáveis Locais

def f(b):
    a = 6          # local a, não afeta o global

Palavra‑chave global

def f(b):
    global a
    a = 6          # altera o a global
Exemplo de uso da palavra global

7.3 Fluxo de Controle Excepcional

Quando ocorre um erro, o fluxo “normal” é interrompido e o interpretador cria um objeto de exceção. Se não houver try/except, o manipulador padrão exibe o traceback e encerra o programa.

Capturando Exceções

try:
    idade = int(input("Idade: "))
    print(f"Você tem {idade} anos.")
except ValueError:
    print("Use apenas dígitos de 0‑9.")

Se o usuário digitar “quinze”, a exceção ValueError é capturada e o programa continua.

Vários except

try:
    f = open(nome)
except IOError:
    print("Erro de I/O")
except ValueError:
    print("Valor inválido")
except:
    print("Outro erro")
Fluxo de exceções

7.4 Módulos como Namespaces

Um módulo é um arquivo .py. Quando importado, o Python cria um namespace cujo nome é o do módulo. Todos os objetos definidos no nível superior (funções, classes, variáveis) tornam‑se atributos desse namespace.

import math
print(math.pi)   # math é o namespace do módulo

Busca de Módulos

O interpretador procura o módulo em sys.path. Se o diretório que contém o arquivo não estiver na lista, a importação falha.

Variável __name__

Quando o módulo é executado como programa principal, __name__ == '__main__'. Isso permite código de teste:

if __name__ == '__main__':
    teste()
Diagrama de importação de módulos

7.5 Classes como Namespaces

Uma classe também possui seu próprio namespace. Os métodos são funções armazenadas nesse namespace. Quando chamamos obj.metodo(), o interpretador traduz para Classe.metodo(obj).

lst = [5,2,8]
lst.sort()          # equivale a list.sort(lst)

Portanto, o primeiro parâmetro de todo método é a própria instância (self).

Classe como namespace

Resumo dos Tópicos

  • 7.1 Encapsulamento em Funções
    • Reutilização de código – colocar trechos repetidos em funções.
    • Modularidade – dividir o problema em partes menores.
    • Encapsulamento – esconder detalhes de implementação.
    • Variáveis locais – criam um namespace próprio para cada chamada.
  • 7.2 Namespaces Globais vs Locais
    • Escopo global: nomes definidos fora de funções (módulo ou shell).
    • Escopo local: nomes definidos dentro de funções.
    • Regra de busca: local → global → built‑ins.
    • Palavra‑chave global permite modificar variáveis globais dentro de funções.
  • 7.3 Fluxo de Controle Excepcional
    • Exceções interrompem o fluxo normal e criam um objeto de erro.
    • Bloco try/except captura exceções e permite tratamento customizado.
    • É possível ter múltiplos except para tipos diferentes.
  • 7.4 Módulos como Namespaces
    • Importar cria um namespace com o nome do módulo.
    • Funções dir() e atributos __name__, __file__, __doc__ ajudam a inspeção.
    • Busca de módulos usa sys.path.
    • Condição if __name__ == '__main__' permite código de teste.
  • 7.5 Classes como Namespaces
    • Cada classe tem seu próprio namespace onde vivem atributos e métodos.
    • Métodos são funções que recebem a instância como primeiro argumento (self).
    • Chamadas de método são traduzidas para chamadas de função no namespace da classe.

Mapa Mental

mindmap root((Namespaces & Controle)) sub1(Encapsulamento) sub1a(Reutilização) sub1b(Modularidade) sub1c(Variáveis Locais) sub2(Escopo) sub2a(Global) sub2b(Local) sub2c(Palavra‑chave global) sub3(Exceções) sub3a(try/except) sub3b(Múltiplos except) sub3c(Fluxo excepcional) sub4(Módulos) sub4a(Namespace do módulo) sub4b(sys.path) sub4c(__name__ == '__main__') sub5(Classes) sub5a(Namespace da classe) sub5b(Métodos → funções) sub5c(self) end

Questões sobre o assunto

1. Considere o código abaixo:
def f(y):
    x = 2
    print(f"x={x}, y={y}")
    g(3)

def g(y):
    x = 4
    print(f"x={x}, y={y}")

Qual será a saída ao executar f(1)?

1.50 pontos Média

Resposta correta: A) x=2, y=1
x=4, y=3

Explicação: f tem seu próprio namespace (x=2, y=1). Dentro de f chama g(3), que cria outro namespace (x=4, y=3).

2. Qual das alternativas descreve corretamente a ordem de busca de um nome em Python?
2.50 pontos Difícil

Resposta correta: C) Local → Global → Built‑ins

O interpretador procura primeiro no namespace local da chamada, depois no global (módulo) e, por fim, nos built‑ins.

3. Analise o módulo example.py abaixo:
# example.py
def f():
    print('f')
def g():
    print('g')
x = 10

Se o módulo for importado com from example import *, qual será o conteúdo de dir() no módulo chamador?

2.50 pontos Difícil

Resposta correta: A) ['f', 'g', 'x']

O wildcard importa todos os nomes que não começam com “_”. Assim, f, g e x ficam no namespace do chamador.

4. Considere o seguinte trecho:
def safe_open(nome, modo):
    try:
        arq = open(nome, modo)
        return arq
    except:
        return None

f = safe_open('inexistente.txt', 'r')
if f is None:
    print('Falha ao abrir')
else:
    print('Arquivo aberto')

Qual é o comportamento correto desse código quando o arquivo não existe?

3.50 pontos Extrema

Resposta correta: B) Imprime “Falha ao abrir”.

Quando open falha, a exceção é capturada, safe_open devolve None e o if imprime a mensagem.

Pontuação Total
0.00