Python & AI Tutorials Logo
Programação Python

24. Entendendo Erros e Tracebacks

Erros são uma parte inevitável da programação. Todo programador, do iniciante ao especialista, esbarra neles regularmente. A diferença entre sofrer com erros e aprender com eles está em entender o que o Python está tentando te dizer quando algo dá errado.

Quando o Python encontra um problema no seu código, ele não apenas para em silêncio — ele fornece informações detalhadas sobre o que deu errado, onde aconteceu e, muitas vezes, dá pistas do porquê. Aprender a ler e interpretar essas mensagens de erro é uma das habilidades mais valiosas que você pode desenvolver como programador.

Neste capítulo, vamos explorar as duas principais categorias de erros que você vai encontrar: erros de sintaxe (syntax errors, problemas em como você escreveu o código) e exceções em tempo de execução (runtime exceptions, problemas que acontecem enquanto o código está rodando). Vamos aprender a ler tracebacks — os relatórios detalhados de erro do Python — e entender como exceções mudam o fluxo normal do seu programa. Mais importante ainda, vamos desenvolver um mindset de debugging que trata erros não como falhas, mas como informações valiosas que te ajudam a escrever um código melhor.

24.1) Erros de Sintaxe vs Exceções em Tempo de Execução

O Python distingue entre dois tipos fundamentalmente diferentes de problemas no seu código: erros de sintaxe e exceções em tempo de execução. Entender essa distinção ajuda você a diagnosticar problemas mais rapidamente e saber onde procurar soluções.

24.1.1) O que são Erros de Sintaxe

Um erro de sintaxe acontece quando o Python não consegue entender seu código porque ele viola as regras gramaticais da linguagem. Assim como "The cat sat on the" é uma frase incompleta em inglês, código com erros de sintaxe é um Python incompleto ou malformado que o interpretador não consegue analisar.

Erros de sintaxe são detectados antes de seu programa rodar. O Python lê seu script inteiro primeiro, verificando se ele segue as regras da linguagem. Se ele encontrar um erro de sintaxe, ele se recusa a executar qualquer parte do código — nem mesmo as partes que estão corretas.

Aqui vai um exemplo simples:

python
# AVISO: Erro de sintaxe - apenas para demonstração
# ERRO: Falta dois-pontos após a instrução if
age = 25
if age >= 18
    print("You are an adult")

Quando você tenta executar esse código, o Python reporta imediatamente:

  File "example.py", line 3
    if age >= 18
                ^
SyntaxError: expected ':'

Repare em várias características importantes dessa mensagem de erro:

  1. Arquivo e número da linha: o Python te diz exatamente onde encontrou o problema (line 3)
  2. Indicador visual: o acento circunflexo (^) aponta para onde o Python ficou confuso
  3. Tipo de erro: SyntaxError identifica claramente que isso é um problema de gramática
  4. Dica útil: expected ':' diz o que está faltando

O código nunca roda porque o Python nem consegue começar a executá-lo — a sintaxe é inválida.

Vamos ver outro erro de sintaxe comum:

python
# AVISO: Erro de sintaxe - apenas para demonstração
# ERRO: Parênteses não correspondentes
numbers = [1, 2, 3, 4, 5]
total = sum(numbers
print(f"Total: {total}")

O Python reporta:

  File "example.py", line 2
    total = sum(numbers
               ^
SyntaxError: '(' was never closed

Aqui, o Python detectou que abrimos um parêntese na linha 2 mas nunca o fechamos. O erro é reportado na linha 2 (onde está o parêntese não fechado), e o acento circunflexo aponta para onde o Python esperava encontrar o parêntese de fechamento.

Principais características de erros de sintaxe:

  • Detectados antes de qualquer código rodar
  • Impedem o programa inteiro de ser executado
  • Normalmente indicam erros de digitação, pontuação faltando ou indentação incorreta
  • O local do erro pode ficar um pouco depois do erro real

24.1.2) O que são Exceções em Tempo de Execução

Uma exceção em tempo de execução — ou simplesmente "exceção" — acontece quando um código sintaticamente correto encontra um problema durante a execução. O código é um Python gramaticalmente válido, mas algo dá errado quando o programa realmente roda.

Diferente dos erros de sintaxe, exceções acontecem enquanto seu programa está rodando. O Python analisou seu código com sucesso e começou a executá-lo, mas então encontrou uma situação que não conseguiu lidar.

Aqui vai um exemplo simples:

python
# Este código tem sintaxe válida, mas vai levantar uma exceção
numbers = [10, 20, 30]
print(numbers[0])  # Output: 10
print(numbers[5])  # Esta linha vai levantar um IndexError
print("This line never executes")

Output:

10
Traceback (most recent call last):
  File "example.py", line 3, in <module>
    print(numbers[5])
          ~~~~~~~^^^
IndexError: list index out of range

Repare no que aconteceu:

  1. A primeira instrução print executou com sucesso (vimos 10)
  2. A segunda print tentou acessar o índice 5, que não existe
  3. O Python levantou uma exceção IndexError
  4. O programa parou, e a terceira print nunca executou

O código estava sintaticamente correto — o Python não teve problema para entender o que queríamos fazer. O problema surgiu durante a execução quando tentamos acessar um elemento da lista que não existia.

Aqui vai outro exemplo mostrando um tipo diferente de exceção em tempo de execução:

python
# Sintaxe válida, mas divisão por zero em tempo de execução
def calculate_average(total, count):
    return total / count
 
# Estes funcionam bem
print(calculate_average(100, 4))  # Output: 25.0
print(calculate_average(75, 3))   # Output: 25.0
 
# Isto levanta uma exceção
print(calculate_average(50, 0))   # ZeroDivisionError

Output:

25.0
25.0
Traceback (most recent call last):
  File "example.py", line 8, in <module>
    print(calculate_average(50, 0))
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 2, in calculate_average
    return total / count
           ~~~~~~^~~~~~~
ZeroDivisionError: division by zero

A função funcionou perfeitamente duas vezes, mas na terceira chamada, passamos 0 como o count, causando uma divisão por zero. O Python não conseguiu detectar esse problema até que o código realmente rodasse com esses valores específicos.

Principais características de exceções em tempo de execução:

  • Ocorrem durante a execução do programa
  • O código é sintaticamente válido
  • Muitas vezes dependem de dados ou condições específicas
  • O programa roda até o ponto em que a exceção ocorre
  • Entradas diferentes podem causar exceções diferentes (ou nenhuma)

24.1.3) Comparando Erros de Sintaxe e Exceções em Tempo de Execução

Vamos ver os dois tipos de erros lado a lado para entender suas diferenças:

python
# Exemplo 1: Erro de Sintaxe
# ERRO: Falta aspas de fechamento
print("Program started!")
message = "Hello, world
print(message)

Isso produz um erro de sintaxe imediatamente:

  File "example.py", line 4
    message = "Hello, world
              ^
SyntaxError: unterminated string literal (detected at line 4)

Importante: Repare que você não vê "Program started!" na saída. O Python detectou o erro de sintaxe antes de executar qualquer código.

Agora compare com uma exceção em tempo de execução:

python
# Exemplo 2: Exceção em Tempo de Execução
# Sintaxe válida, mas a variável não existe
print("Program started!")
message = "Hello, world"
print(mesage)  # Erro de digitação: 'mesage' em vez de 'message'

Output:

Program started!
Traceback (most recent call last):
  File "example.py", line 5, in <module>
    print(mesage)
          ^^^^^^
NameError: name 'mesage' is not defined

Importante: Desta vez você "Program started!" na saída. O Python executou com sucesso as duas primeiras instruções print e de atribuição (linhas 3-4), mas encontrou um problema na linha 5 ao tentar encontrar mesage.

A diferença principal: No primeiro exemplo, o Python nem tentou rodar o código — ele encontrou o erro de sintaxe durante a análise. No segundo exemplo, o Python iniciou a execução do programa com sucesso e rodou várias linhas antes de encontrar o erro em tempo de execução.

Não

Sim

Não

Sim

Python Lê Seu Código

Sintaxe Válida?

Erro de Sintaxe
Programa Nunca Roda

Programa Começa a Executar

Problema Durante
a Execução?

Programa Termina
com Sucesso

Exceção em Tempo de Execução
Programa Para

24.2) Tipos Comuns de Exceções Built-in

O Python tem muitos tipos de exceção built-in, cada um representando um tipo específico de problema. Aprender a reconhecer essas exceções comuns ajuda você a entender rapidamente o que deu errado e como corrigir. Cada tipo de exceção tem um nome descritivo que dá uma pista sobre o problema.

24.2.1) NameError: Usando Nomes Não Definidos

Um NameError acontece quando você tenta usar uma variável, função ou outro nome que o Python não reconhece. Isso geralmente significa que você esqueceu de definir algo, escreveu um nome errado ou está tentando usar algo antes de ele ser criado.

python
# Exemplo 1: Esqueceu de definir uma variável
print(greeting)  # NameError: name 'greeting' is not defined

Output:

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    print(greeting)
          ^^^^^^^^
NameError: name 'greeting' is not defined

O Python está dizendo que não sabe o que é greeting. Você precisa criá-la primeiro:

python
# Versão correta
greeting = "Hello, Python!"
print(greeting)  # Output: Hello, Python!

Aqui vai um exemplo mais sutil com um erro de digitação:

python
# Exemplo 2: Erro de digitação no nome da variável
user_name = "Alice"
age = 30
 
print(f"{username} is {age} years old")  # NameError: name 'username' is not defined

Nós definimos user_name (com sublinhado), mas tentamos usar username (sem sublinhado). O Python vê esses nomes como completamente diferentes.

24.2.2) TypeError: Tipo Errado para uma Operação

Um TypeError acontece quando você tenta fazer uma operação em um valor do tipo errado. Por exemplo, você não pode somar uma string com um inteiro, ou chamar algo que não é uma função.

python
# Exemplo 1: Misturando tipos incompatíveis
age = 25
message = "You are " + age + " years old"  # TypeError

Output:

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    message = "You are " + age + " years old"
              ~~~~~~~~~~~~^~~~~
TypeError: can only concatenate str (not "int") to str

O Python está te dizendo que o operador + pode concatenar strings com strings, mas não strings com inteiros. Você precisa converter o inteiro para string:

python
# Versão correta
age = 25
message = "You are " + str(age) + " years old"
print(message)  # Output: You are 25 years old

TypeErrors também acontecem quando você passa o número errado de argumentos para uma função:

python
# Exemplo 3: Número errado de argumentos
def calculate_area(length, width):
    return length * width
 
area = calculate_area(5)  # TypeError: missing 1 required positional argument

Output:

Traceback (most recent call last):
  File "example.py", line 4, in <module>
    area = calculate_area(5)
TypeError: calculate_area() missing 1 required positional argument: 'width'

A função espera dois argumentos, mas nós fornecemos apenas um.

24.2.3) ValueError: Tipo Certo, Valor Errado

Um ValueError acontece quando você passa um valor do tipo correto, mas o valor em si é inadequado para a operação. O tipo está certo, mas o valor específico não faz sentido naquele contexto.

python
# Exemplo 1: Convertendo string inválida para inteiro
user_input = "twenty-five"
age = int(user_input)  # ValueError: invalid literal for int()

Output:

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    age = int(user_input)
ValueError: invalid literal for int() with base 10: 'twenty-five'

A função int() espera uma string, e nós demos uma string — então o tipo está correto. Mas a string "twenty-five" não pode ser convertida para um inteiro porque contém letras. A string "25" funcionaria sem problema:

python
# Versão correta
user_input = "25"
age = int(user_input)
print(age)  # Output: 25

ValueErrors também acontecem com métodos de lista:

python
# Exemplo 3: Removendo item que não existe
fruits = ["apple", "banana", "orange"]
fruits.remove("grape")  # ValueError: 'grape' is not in list

Output:

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    fruits.remove("grape")
    ~~~~~~~~~~~~~^^^^^^^^^
ValueError: list.remove(x): x not in list

O método remove() espera um valor que exista na lista. Devemos verificar antes:

python
# Versão correta
fruits = ["apple", "banana", "orange"]
if "grape" in fruits:
    fruits.remove("grape")
else:
    print("Grape not found in list")  # Output: Grape not found in list

24.2.4) IndexError: Índice de Sequência Inválido

Um IndexError acontece quando você tenta acessar uma sequência (lista, tupla, string) usando um índice que não existe. Lembre que o Python usa indexação baseada em zero, e índices válidos vão de 0 a len(sequence) - 1.

python
# Exemplo 1: Índice grande demais
colors = ["red", "green", "blue"]
print(colors[0])  # Output: red
print(colors[3])  # IndexError: list index out of range

Output:

red
Traceback (most recent call last):
  File "example.py", line 3, in <module>
    print(colors[3])
          ~~~~~~^^^
IndexError: list index out of range

A lista tem três elementos nos índices 0, 1 e 2. O índice 3 não existe. Esse é um erro muito comum quando você esquece que a indexação começa em 0:

python
# Versão correta
colors = ["red", "green", "blue"]
print(colors[2])  # Output: blue (the third element)

24.2.5) KeyError: Chave de Dicionário Ausente

Um KeyError acontece quando você tenta acessar uma chave de dicionário que não existe. Diferente de listas onde você pode verificar o comprimento, dicionários podem ter qualquer chave, então você precisa confirmar que a chave existe antes de acessá-la.

python
# Exemplo 1: Acessando chave que não existe
student = {
    "name": "Alice",
    "age": 20,
    "major": "Computer Science"
}
 
print(student["name"])   # Output: Alice
print(student["grade"])  # KeyError: 'grade'

Output:

Alice
Traceback (most recent call last):
  File "example.py", line 7, in <module>
    print(student["grade"])
          ~~~~~~~^^^^^^^^^
KeyError: 'grade'

O dicionário não tem a chave "grade". Você pode verificar se a chave existe primeiro:

python
# Versão correta usando 'in'
student = {
    "name": "Alice",
    "age": 20,
    "major": "Computer Science"
}
 
if "grade" in student:
    print(student["grade"])
else:
    print("Grade not available")  # Output: Grade not available

Ou usar o método get(), que retorna None (ou um valor padrão) em vez de levantar um erro:

python
# Alternativa usando get()
grade = student.get("grade")
if grade is not None:
    print(f"Grade: {grade}")
else:
    print("Grade not available")  # Output: Grade not available

KeyErrors normalmente acontecem ao processar dados com estrutura inconsistente:

python
# Exemplo 2: Processando múltiplos registros
students = [
    {"name": "Alice", "age": 20, "grade": "A"},
    {"name": "Bob", "age": 21},  # Falta a chave 'grade'
    {"name": "Carol", "age": 19, "grade": "B"}
]
 
for student in students:
    print(f"{student['name']}: {student['grade']}")  # KeyError on Bob

Output:

Alice: A
Traceback (most recent call last):
  File "example.py", line 7, in <module>
    print(f"{student['name']}: {student['grade']}")
                                ~~~~~~~^^^^^^^^^
KeyError: 'grade'

Use get() com um valor padrão para lidar com chaves ausentes de forma elegante:

python
# Versão correta
students = [
    {"name": "Alice", "age": 20, "grade": "A"},
    {"name": "Bob", "age": 21},
    {"name": "Carol", "age": 19, "grade": "B"}
]
 
for student in students:
    grade = student.get("grade", "Not assigned")
    print(f"{student['name']}: {grade}")

Output:

Alice: A
Bob: Not assigned
Carol: B

24.2.6) AttributeError: Acesso a Atributo Inválido

Um AttributeError acontece quando você tenta acessar um atributo ou método que não existe em um objeto. Isso frequentemente acontece quando você confunde métodos entre tipos diferentes ou escreve nomes de atributos errados.

python
# Exemplo 1: Método errado para o tipo
numbers = [1, 2, 3, 4, 5]
numbers.append(6)  # Isto funciona - listas têm append()
print(numbers)     # Output: [1, 2, 3, 4, 5, 6]
 
text = "Hello"
text.append("!")   # AttributeError: 'str' object has no attribute 'append'

Output:

[1, 2, 3, 4, 5, 6]
Traceback (most recent call last):
  File "example.py", line 6, in <module>
    text.append("!")
    ^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'append'

Strings não têm um método append() porque são imutáveis. Você precisa usar concatenação ou outros métodos de string:

python
# Versão correta
text = "Hello"
text = text + "!"  # Concatenação
print(text)        # Output: Hello!

AttributeErrors também acontecem com erros de digitação:

python
# Exemplo 2: Nome do método escrito errado
message = "Python Programming"
result = message.uppper()  # AttributeError: 'str' object has no attribute 'uppper'

Output:

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    result = message.uppper()
             ^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'uppper'. Did you mean: 'upper'?

Repare que o Python 3.10+ muitas vezes sugere a grafia correta! O método correto é upper():

python
# Versão correta
message = "Python Programming"
result = message.upper()
print(result)  # Output: PYTHON PROGRAMMING

24.2.7) ZeroDivisionError: Divisão por Zero

Um ZeroDivisionError acontece quando você tenta dividir um número por zero, o que é matematicamente indefinido. Isso frequentemente acontece com entrada do usuário ou valores calculados que você não esperava que fossem zero.

python
# Exemplo 1: Divisão direta por zero
result = 10 / 0  # ZeroDivisionError: division by zero

Output:

Traceback (most recent call last):
  File "example.py", line 1, in <module>
    result = 10 / 0
             ~~~^~~
ZeroDivisionError: division by zero

Isso também se aplica à divisão inteira e ao módulo:

python
# Exemplo 2: Outras operações de divisão
a = 10 // 0  # ZeroDivisionError
b = 10 % 0   # ZeroDivisionError

Um exemplo mais realista envolve cálculos:

python
# Exemplo 3: Calculando média
def calculate_average(numbers):
    total = sum(numbers)
    count = len(numbers)
    return total / count
 
scores = [85, 90, 78, 92]
print(calculate_average(scores))  # Output: 86.25
 
empty_scores = []
print(calculate_average(empty_scores))  # ZeroDivisionError

Output:

86.25
Traceback (most recent call last):
  File "example.py", line 9, in <module>
    print(calculate_average(empty_scores))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 4, in calculate_average
    return total / count
           ~~~~~~^~~~~~~
ZeroDivisionError: division by zero

Uma lista vazia tem comprimento 0, causando divisão por zero. Sempre verifique essa condição:

python
# Versão correta
def calculate_average(numbers):
    if len(numbers) == 0:
        return 0  # Or return None, or raise a more descriptive error
    
    total = sum(numbers)
    count = len(numbers)
    return total / count
 
scores = [85, 90, 78, 92]
print(calculate_average(scores))  # Output: 86.25
 
empty_scores = []
print(calculate_average(empty_scores))  # Output: 0

Tipos Comuns de Exceção

NameError
Variável/função não definida

TypeError
Tipo errado para operação

ValueError
Tipo certo, valor errado

IndexError
Índice de sequência inválido

KeyError
Chave de dicionário ausente

AttributeError
Atributo/método inválido

ZeroDivisionError
Divisão por zero

Entender esses tipos comuns de exceção ajuda você a diagnosticar problemas rapidamente. Quando você vê uma exceção, o nome do tipo imediatamente te diz em que categoria de problema ela se encaixa, e a mensagem de erro fornece detalhes específicos sobre o que deu errado.

24.3) Lendo e Interpretando Tracebacks em Detalhe

Quando uma exceção em tempo de execução acontece, o Python não apenas te diz o que deu errado — ele fornece um traceback detalhado mostrando exatamente como seu programa chegou àquele ponto. Aprender a ler tracebacks é essencial para um debugging eficaz. Um traceback é como uma trilha de migalhas de pão mostrando o caminho que seu programa percorreu antes de encontrar o erro.

24.3.1) Anatomia de um Traceback

Vamos começar com um exemplo simples e examinar cada parte do traceback:

python
# Programa simples com um erro
def calculate_discount(price, discount_percent):
    discount_amount = price * (discount_percent / 100)
    final_price = price - discount_amount
    return final_price
 
def process_order(item_price, discount):
    discounted_price = calculate_discount(item_price, discount)
    tax = discounted_price * 0.08
    total = discounted_price + tax
    return total
 
# Programa principal
original_price = "50"  # Ops! Isto deveria ser um número
discount_rate = 10
final_cost = process_order(original_price, discount_rate)
print(f"Final cost: ${final_cost:.2f}")

Output:

Traceback (most recent call last):
  File "example.py", line 16, in <module>
    final_cost = process_order(original_price, discount_rate)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 8, in process_order
    discounted_price = calculate_discount(item_price, discount)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 2, in calculate_discount
    discount_amount = price * (discount_percent / 100)
                      ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'

Vamos destrinchar cada componente desse traceback:

1. O cabeçalho: "Traceback (most recent call last):"

Essa linha diz que o que vem a seguir é um traceback — um registro de chamadas de função. A frase "most recent call last" significa que o traceback é mostrado em ordem cronológica: a primeira função chamada aparece primeiro, e o local onde o erro realmente ocorreu aparece por último.

2. A pilha de chamadas (lendo de cima para baixo):

  File "example.py", line 16, in <module>
    final_cost = process_order(original_price, discount_rate)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Esta é a primeira chamada de função na cadeia. Ela mostra:

  • Nome do arquivo: "example.py" - onde o código está
  • Número da linha: line 16 - a linha exata que fez essa chamada
  • Contexto: in <module> - esse código está no nível superior (não dentro de uma função)
  • Código: a linha real que foi executada
  • Destaque: os caracteres ^ apontam para a parte específica da linha envolvida

O contexto <module> significa que esse é um código executando no nível do módulo (a parte principal do seu script), e não dentro de uma função.

  File "example.py", line 8, in process_order
    discounted_price = calculate_discount(item_price, discount)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Esta é a segunda chamada de função. A função process_order foi chamada da linha 16, e agora estamos dentro dessa função na linha 8, onde ela chama calculate_discount.

  File "example.py", line 2, in calculate_discount
    discount_amount = price * (discount_percent / 100)
                      ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

É aqui que o erro de fato aconteceu. Agora estamos dentro da função calculate_discount na linha 2, e esta é a linha que causou o problema.

3. A mensagem de erro:

TypeError: can't multiply sequence by non-int of type 'float'

Este é o erro real que aconteceu:

  • Tipo de exceção: TypeError - diz a categoria do erro
  • Descrição: o restante explica especificamente o que deu errado

Neste caso, o Python está dizendo que tentamos multiplicar uma sequência (uma string, neste caso) por um float, o que não é permitido.

24.3.2) Lendo o Traceback de Baixo para Cima

Embora o traceback seja impresso em ordem cronológica (de cima para baixo), programadores experientes frequentemente o leem de baixo para cima porque o erro real está embaixo, e as linhas acima mostram como chegamos lá.

Vamos ler nosso traceback anterior de baixo para cima:

Passo 1: Comece com a mensagem de erro

TypeError: can't multiply sequence by non-int of type 'float'

"Certo, nós tentamos multiplicar uma sequência por um float. Isso não é permitido."

Passo 2: Veja onde o erro aconteceu

  File "example.py", line 2, in calculate_discount
    discount_amount = price * (discount_percent / 100)
                      ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

"O erro aconteceu na função calculate_discount na linha 2. Estamos tentando multiplicar price por alguma coisa."

Passo 3: Volte para ver como chegamos lá

  File "example.py", line 8, in process_order
    discounted_price = calculate_discount(item_price, discount)

"A função calculate_discount foi chamada a partir de process_order na linha 8, passando item_price como o parâmetro price."

Passo 4: Continue voltando

  File "example.py", line 16, in <module>
    final_cost = process_order(original_price, discount_rate)

"E process_order foi chamada a partir do programa principal na linha 16, passando original_price como item_price."

Passo 5: Encontre a causa raiz

Agora conseguimos rastrear o problema: original_price é "50" (uma string), que é passada como item_price para process_order, que a passa como price para calculate_discount, onde tentamos multiplicá-la por um float. A solução é fazer original_price ser um número:

python
# Versão corrigida
def calculate_discount(price, discount_percent):
    discount_amount = price * (discount_percent / 100)
    final_price = price - discount_amount
    return final_price
 
def process_order(item_price, discount):
    discounted_price = calculate_discount(item_price, discount)
    tax = discounted_price * 0.08
    total = discounted_price + tax
    return total
 
# Programa principal - corrigimos o tipo
original_price = 50  # Agora é um número, não uma string
discount_rate = 10
final_cost = process_order(original_price, discount_rate)
print(f"Final cost: ${final_cost:.2f}")  # Output: Final cost: $48.60

Ler o Traceback

1. Ler a Mensagem de Erro
Linha de Baixo
2. Encontrar o Local do Erro
Último Bloco de Código
3. Rastrear a Pilha de Chamadas
Subir
4. Formular Hipótese
O que Deu Errado?
5. Verificar e Corrigir
Testar Sua Solução

Entender como ler tracebacks transforma essas paredes de texto intimidadoras em ferramentas úteis de debugging. Cada linha fornece informações valiosas sobre o caminho de execução do seu programa e, com prática, você vai conseguir identificar e corrigir problemas rapidamente seguindo a orientação do traceback.

24.4) Como Exceções Mudam o Fluxo Normal de um Programa

Quando uma exceção acontece, ela não apenas para seu programa — ela muda fundamentalmente como o programa executa. Entender esse comportamento é crucial para escrever código robusto e para entender o que acontece quando erros ocorrem.

24.4.1) Fluxo Normal do Programa vs Fluxo com Exceção

Na execução normal, o Python roda seu código linha por linha, de cima para baixo:

python
# Fluxo normal do programa
print("Step 1: Starting calculation")
result = 10 + 5
print(f"Step 2: Result is {result}")
final = result * 2
print(f"Step 3: Final value is {final}")
print("Step 4: Program complete")

Output:

Step 1: Starting calculation
Step 2: Result is 15
Step 3: Final value is 30
Step 4: Program complete

Cada linha executa em ordem. Agora vamos ver o que acontece quando ocorre uma exceção:

python
# Fluxo do programa com uma exceção
print("Step 1: Starting calculation")
result = 10 / 0  # Isto levanta ZeroDivisionError
print(f"Step 2: Result is {result}")  # Isto nunca executa
final = result * 2  # Isto nunca executa
print(f"Step 3: Final value is {final}")  # Isto nunca executa
print("Step 4: Program complete")  # Isto nunca executa

Output:

Step 1: Starting calculation
Traceback (most recent call last):
  File "example.py", line 2, in <module>
    result = 10 / 0
             ~~~^~~
ZeroDivisionError: division by zero

Repare que apenas a primeira instrução print executou. Assim que a exceção aconteceu na linha 2, o Python parou de executar o restante do código. A exceção interrompeu o fluxo normal.

24.4.2) Exceções se Propagam pela Pilha de Chamadas

Quando uma exceção acontece dentro de uma função, o Python não para apenas naquela função — ele propaga (sobe) pela pilha de chamadas até que algo a trate ou o programa termine.

python
# Exemplo 1: Exceção se propagando por funções
def calculate_average(numbers):
    total = sum(numbers)
    count = len(numbers)
    return total / count  # Pode levantar ZeroDivisionError
 
def process_scores(score_list):
    print("Processing scores...")
    avg = calculate_average(score_list)
    print(f"Average calculated: {avg}")
    return avg
 
def main():
    print("Program starting")
    scores = []  # Lista vazia
    result = process_scores(scores)
    print(f"Final result: {result}")
    print("Program ending")
 
main()

Output:

Program starting
Processing scores...
Traceback (most recent call last):
  File "example.py", line 18, in <module>
    main()
  File "example.py", line 14, in main
    result = process_scores(scores)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 9, in process_scores
    avg = calculate_average(score_list)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 4, in calculate_average
    return total / count
           ~~~~~~^~~~~~~
ZeroDivisionError: division by zero

Vamos rastrear o que aconteceu:

  1. main() começou a executar e imprimiu "Program starting"
  2. main() chamou process_scores()
  3. process_scores() imprimiu "Processing scores..."
  4. process_scores() chamou calculate_average()
  5. calculate_average() tentou dividir por zero
  6. A exceção aconteceu e se propagou:
    • calculate_average() parou imediatamente (não retornou um valor)
    • O controle voltou para process_scores(), mas não normalmente — a exceção continuou se propagando
    • process_scores() parou imediatamente (o print depois de calculate_average() nunca executou)
    • O controle voltou para main(), mas novamente, a exceção continuou se propagando
    • main() parou imediatamente (os prints depois de process_scores() nunca executaram)
  7. O programa terminou com o traceback

Nenhum código após a exceção executou em nenhuma das funções. A exceção "borbulhou" por todas as chamadas de função até atingir o nível superior e encerrar o programa.

24.5) Mindset de Debugging: Tratando Erros como Informação, Não como Falhas

Uma das habilidades mais importantes em programação não é escrever código perfeito — é aprender a trabalhar de forma eficaz com código imperfeito. Todo programador, independentemente do nível de experiência, escreve código que produz erros. A diferença entre programadores que sofrem e programadores eficazes não está em evitar erros, mas em como eles reagem a eles.

24.5.1) Erros Não São Falhas

Quando você está aprendendo a programar, é natural ficar frustrado quando encontra erros. Você pode sentir que fez algo errado ou que não está "entendendo". Esse mindset é contraproducente e, mais importante, incorreto.

Erros não são falhas — são feedback.

Pense em erros como um GPS recalculando sua rota. Quando você perde uma entrada, o GPS não diz "Você falhou!". Ele diz "Recalculando rota" e te dá novas instruções. As mensagens de erro do Python funcionam do mesmo jeito: elas estão te dizendo que o caminho que você seguiu não funcionou e estão fornecendo informações para ajudar você a encontrar um caminho que funcione.

Considere este exemplo simples:

python
# Primeira tentativa de calcular média
def calculate_average(numbers):
    total = sum(numbers)
    average = total / len(numbers)
    return average
 
scores = []
result = calculate_average(scores)
print(f"Average: {result}")

Output:

Traceback (most recent call last):
  File "example.py", line 8, in <module>
    result = calculate_average(scores)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "example.py", line 4, in calculate_average
    average = total / len(numbers)
              ~~~~~~^~~~~~~~~~~~~~
ZeroDivisionError: division by zero

Esse erro não está dizendo que você é um mau programador. Ele está dizendo algo específico e útil: "Você tentou dividir por zero, o que acontece quando a lista está vazia. Você precisa tratar esse caso."

Com essa informação em mãos, você pode melhorar seu código:

python
# Versão melhorada com base no feedback do erro
def calculate_average(numbers):
    if len(numbers) == 0:
        return 0  # Or return None, or raise a more descriptive error
    
    total = sum(numbers)
    average = total / len(numbers)
    return average
 
scores = []
result = calculate_average(scores)
print(f"Average: {result}")  # Output: Average: 0

O erro te ajudou a escrever um código melhor. Sem esse erro, você talvez não percebesse que sua função não conseguia lidar com listas vazias.

24.5.2) Todo Erro te Ensina Algo

Cada erro que você encontra te ensina algo sobre Python, sobre seu código, ou sobre programação em geral. Vamos ver vários exemplos do que diferentes erros nos ensinam:

Exemplo 1: Aprendendo sobre tipos

python
# Tentando somar tipos incompatíveis
age = 25
message = "You are " + age + " years old"

Output:

TypeError: can only concatenate str (not "int") to str

O que isso ensina: O Python tem regras rígidas de tipos. Você não pode misturar strings e números em concatenação. Esse erro te ensina sobre compatibilidade de tipos e te apresenta ao conceito de conversão de tipos.

Exemplo 2: Aprendendo sobre estruturas de dados

python
# Tentando acessar um dicionário como se fosse uma lista
student = {"name": "Alice", "age": 20}
first_value = student[0]

Output:

KeyError: 0

O que isso ensina: Dicionários usam chaves, não índices numéricos. Esse erro te ensina sobre a diferença entre dicionários e listas, e como acessar valores de dicionários corretamente.

Exemplo 3: Aprendendo sobre escopo

python
# Tentando usar uma variável antes de defini-la
def greet():
    print(f"Hello, {name}!")
 
greet()
name = "Alice"

Output:

NameError: name 'name' is not defined

O que isso ensina: Variáveis precisam ser definidas antes de serem usadas, e a ordem de execução importa. Esse erro te ensina sobre escopo de variáveis e a importância da inicialização.

Cada um desses erros fornece informações específicas e acionáveis que ajudam você a entender Python melhor. Em vez de vê-los como obstáculos, veja-os como oportunidades de aprendizado.

24.5.3) Abraçando o Mindset de Debugging

Programadores profissionais passam uma parte significativa do tempo fazendo debugging. Não é um sinal de fraqueza — é uma parte central do trabalho. Os melhores programadores não são aqueles que nunca cometem erros; são aqueles que:

  1. Esperam erros: eles sabem que erros vão acontecer e não ficam surpresos ou desanimados
  2. Leem os erros com atenção: eles extraem o máximo de informação das mensagens de erro
  3. Fazem debugging de forma sistemática: eles seguem um processo lógico em vez de fazer mudanças aleatórias
  4. Aprendem com os erros: eles usam cada erro como uma oportunidade para entender Python melhor
  5. Mantêm a curiosidade: eles perguntam "Por que isso aconteceu?" em vez de apenas "Como eu conserto isso?"

Não

Sim

Não

Sim

Encontrar um Erro

Ler a Mensagem de Erro
com Atenção

Entender o que
Deu Errado

Formular uma Hipótese
sobre a Causa

Testar a Hipótese
com Saída de Debug

Hipótese
Correta?

Implementar a Correção

Testar a Solução

Funciona
Corretamente?

Aprender com a
Experiência

Seguir em Frente
com Confiança

Lembre: todo erro é uma oportunidade de aprender algo novo sobre Python, sobre programação ou sobre resolução de problemas. Encare erros como feedback valioso, aborde-os sistematicamente e celebre seus sucessos de debugging. Esse mindset vai te servir durante toda a sua jornada na programação.


Entender erros e tracebacks é fundamental para se tornar um programador Python eficaz. Neste capítulo, aprendemos a distinguir entre erros de sintaxe (problemas na estrutura do código) e exceções em tempo de execução (problemas durante a execução), reconhecer tipos comuns de exceção e o que eles indicam, ler e interpretar tracebacks detalhados para encontrar a causa raiz dos problemas, entender como exceções mudam o fluxo do programa ao se propagarem pela pilha de chamadas e desenvolver um mindset de debugging que trata erros como informação valiosa em vez de falhas.

Essas habilidades formam a base para o próximo capítulo, onde vamos aprender a tratar exceções de forma elegante usando blocos try e except, permitindo que nossos programas se recuperem de erros e continuem rodando. Mas antes de conseguirmos tratar exceções de forma eficaz, precisamos entendê-las a fundo — e foi exatamente isso que realizamos aqui.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai