Capítulo 8: Conteúdo Extra#

Tratamento de erros (try/except)#
Em Python, usamos o bloco try/except para lidar com erros que podem ocorrer durante a execução do programa, evitando que ele seja interrompido inesperadamente.
Exemplo básico com try/except:
try:
numero = int(input("Digite um número: "))
resultado = 10 / numero
print(f"O resultado é {resultado}.")
except ZeroDivisionError:
print("Erro: divisão por zero.")
except ValueError:
print("Erro: entrada inválida.")
Saída:
Digite um número: 2
O resultado é 5.0.
Digite um número: 0
Erro: divisão por zero.
Digite um número: abc
Erro: entrada inválida.
Blocos else e finally no tratamento de erros#
Além do try e except, Python permite o uso opcional dos blocos else e finally para tornar o tratamento de erros mais completo.
else
Executado somente se nenhum erro ocorrer no bloco try.
finally
Executado sempre, com ou sem erro. É útil para liberar recursos, como fechar arquivos ou conexões com banco de dados.
Exemplo com else e finally:
try:
numero = int(input("Digite um número: "))
resultado = 10 / numero
except ZeroDivisionError:
print("Erro: divisão por zero.")
except ValueError:
print("Erro: entrada inválida.")
else:
print(f"O resultado é {resultado}.")
finally:
print("Execução finalizada.")
Saída:
Digite um número: 2
O resultado é 5.0.
Execução finalizada.
Digite um número: 0
Erro: divisão por zero.
Execução finalizada.
Digite um número: xyz
Erro: entrada inválida.
Execução finalizada.
Usando try/except em funções#
É comum usar try/except dentro de funções para torná-las mais seguras e reutilizáveis.
def dividir(a, b):
try:
return a / b
except ZeroDivisionError:
return "Erro: divisão por zero."
print(dividir(10, 2)) # Saída: 5.0
print(dividir(10, 0)) # Saída: Erro: divisão por zero.
Saída:
5.0
Erro: divisão por zero.
Tabela com Resumo#
Bloco |
Quando é executado |
|---|---|
|
Tenta executar um código que pode dar erro |
|
Executa se um erro ocorrer no |
|
Executa se nenhum erro ocorrer no |
|
Sempre executa, com ou sem erro |
Manipulação de arquivos#
Até agora, os dados dos nossos programas viviam apenas na memória: assim que o programa terminava, tudo se perdia. Para guardar informações de forma permanente (um relatório, uma lista de tarefas, configurações), gravamos os dados em arquivos.
Abrindo um arquivo: a função open()#
Para trabalhar com um arquivo, primeiro o abrimos com open(), informando o caminho e o modo de abertura:
arquivo = open("dados.txt", "r", encoding="utf-8")
O modo define o que podemos fazer com o arquivo:
Modo |
Significado |
Se o arquivo não existe |
|---|---|---|
|
leitura (read) |
gera erro |
|
escrita (write), apaga o conteúdo anterior |
cria um novo |
|
acréscimo (append), escreve no final |
cria um novo |
|
criação exclusiva |
cria; erro se já existir |
|
modo binário (combina com os outros, ex.: |
não se aplica |
O parâmetro encoding="utf-8" garante que acentos e caracteres especiais sejam lidos e gravados corretamente.
O jeito certo: o bloco with#
Todo arquivo aberto precisa ser fechado para liberar os recursos do sistema. Em vez de chamar arquivo.close() na mão (e correr o risco de esquecer, ou de o programa falhar antes disso), usamos o bloco with, que fecha o arquivo automaticamente ao final, mesmo que ocorra um erro:
with open("zen.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("Bonito é melhor que feio.\n")
arquivo.write("Explícito é melhor que implícito.\n")
arquivo.write("Simples é melhor que complexo.\n")
# fora do with, o arquivo já está fechado
Boa prática - sempre use o with
Prefira sempre o with open(...) as ...:. Ele cuida do fechamento do arquivo para você, evitando vazamento de recursos e arquivos corrompidos. É o mesmo papel do bloco finally que vimos no try/except.
Lendo um arquivo#
Há algumas formas de ler o conteúdo de um arquivo aberto em modo leitura. A mais direta lê tudo de uma vez:
with open("zen.txt", "r", encoding="utf-8") as arquivo:
conteudo = arquivo.read() # lê o arquivo inteiro como uma única string
print(conteudo)
Para arquivos grandes, ler linha a linha é mais eficiente. O próprio arquivo é iterável:
with open("zen.txt", "r", encoding="utf-8") as arquivo:
for linha in arquivo:
print(linha.strip()) # strip() remove o "\n" do final de cada linha
Saída:
Bonito é melhor que feio.
Explícito é melhor que implícito.
Simples é melhor que complexo.
Outros métodos úteis são readline() (lê uma linha por vez) e readlines() (devolve uma lista com todas as linhas).
Atenção - o modo de escrita apaga o conteúdo
Abrir um arquivo existente em modo "w" apaga todo o conteúdo anterior antes de escrever. Para adicionar informações sem perder o que já existe, use o modo "a" (append).
Juntando com o tratamento de erros#
Operações com arquivos falham por vários motivos (o arquivo não existe, falta de permissão). Por isso, é comum combinar arquivos com try/except:
try:
with open("inexistente.txt", "r", encoding="utf-8") as arquivo:
print(arquivo.read())
except FileNotFoundError:
print("Erro: o arquivo não foi encontrado.")
Saída:
Erro: o arquivo não foi encontrado.
Dados do mundo real: datas, JSON e CSV#
Projetos reais lidam o tempo todo com datas, com dados estruturados (JSON) e com tabelas e planilhas (CSV). A biblioteca padrão do Python já traz módulos prontos para os três.
Datas e horas com datetime#
O módulo datetime representa datas e horários e permite fazer contas com eles:
from datetime import datetime, timedelta
agora = datetime.now()
print(agora) # ex.: 2024-05-04 14:30:00.123456
# Criando uma data específica (ano, mês, dia, hora, minuto)
estreia = datetime(1975, 4, 3, 20, 0)
print(estreia.year, estreia.month) # 1975 4
Para exibir uma data em um formato legível usamos strftime(); para interpretar uma data escrita em texto usamos strptime():
agora = datetime.now()
print(agora.strftime("%d/%m/%Y às %H:%M")) # ex.: 04/05/2024 às 14:30
texto = "03/04/1975"
data = datetime.strptime(texto, "%d/%m/%Y")
print(data.year) # 1975
A diferença entre duas datas vira um timedelta, com o qual fazemos aritmética de tempo:
estreia_na_tv = datetime(1969, 10, 5) # primeiro episódio do Monty Python
hoje = datetime.now()
dias_passados = (hoje - estreia_na_tv).days
print(f"Já se passaram {dias_passados} dias.")
daqui_uma_semana = hoje + timedelta(days=7)
Dica - principais códigos de formatação
Os códigos mais comuns do strftime e do strptime são %d (dia), %m (mês), %Y (ano com 4 dígitos), %H (hora), %M (minuto) e %S (segundo).
JSON: salvando dados estruturados#
O JSON é o formato mais usado para troca de dados entre programas e na web. O módulo json converte entre dicionários e listas do Python e o texto no formato JSON:
import json
personagem = {
"nome": "Rei Arthur",
"filme": "Monty Python em Busca do Cálice Sagrado",
"tem_cavalo": False,
"cavaleiros": ["Lancelot", "Galahad", "Robin"],
}
# dict -> string JSON
texto_json = json.dumps(personagem, indent=2, ensure_ascii=False)
print(texto_json)
# string JSON -> dict
de_volta = json.loads(texto_json)
print(de_volta["nome"]) # Rei Arthur
Para ler e gravar direto em arquivos, use json.dump() e json.load():
# Grava o dicionário em um arquivo .json
with open("personagem.json", "w", encoding="utf-8") as f:
json.dump(personagem, f, indent=2, ensure_ascii=False)
# Lê o arquivo de volta para um dicionário
with open("personagem.json", "r", encoding="utf-8") as f:
dados = json.load(f)
Dica - JSON legível e com acentos
Use indent=2 para gerar um JSON identado (mais fácil de ler) e ensure_ascii=False para manter acentos e caracteres especiais em vez de códigos como á.
Repare no padrão: dumps e loads (com “s” de string) trabalham com texto, enquanto dump e load trabalham diretamente com arquivos.
CSV: tabelas e planilhas#
O CSV (Comma-Separated Values) guarda dados em forma de tabela, com uma linha por registro e os valores separados por vírgula. É o formato que planilhas como o Excel exportam. O módulo csv lê e escreve esses arquivos:
import csv
filmes = [
["titulo", "ano"],
["Em Busca do Cálice Sagrado", 1975],
["A Vida de Brian", 1979],
["O Sentido da Vida", 1983],
]
# Escrevendo (newline="" evita linhas em branco extras)
with open("filmes.csv", "w", newline="", encoding="utf-8") as f:
escritor = csv.writer(f)
escritor.writerows(filmes)
# Lendo de volta
with open("filmes.csv", "r", encoding="utf-8") as f:
leitor = csv.reader(f)
for linha in leitor:
print(linha)
Saída:
['titulo', 'ano']
['Em Busca do Cálice Sagrado', '1975']
['A Vida de Brian', '1979']
['O Sentido da Vida', '1983']
Note que o CSV não guarda o tipo dos dados: o ano 1975 volta da leitura como a string '1975'. Quando cada coluna tem um nome, csv.DictReader e csv.DictWriter deixam o código mais claro, lendo cada linha como um dicionário.
Para ir além - a biblioteca pandas
Para análises mais sérias de tabelas (filtros, estatísticas, gráficos), a biblioteca pandas é o padrão da área. O módulo csv da biblioteca padrão é suficiente para tarefas simples e não exige instalação.
Módulos, pacotes e ambientes virtuais#
À medida que os programas crescem, deixamos de escrever tudo em um único arquivo. Organizamos o código em módulos e pacotes, e reaproveitamos bibliotecas escritas por outras pessoas.
Módulos: reaproveitando código#
Um módulo é simplesmente um arquivo .py. Já usamos vários módulos da biblioteca padrão, como o random e o datetime. Para usar um módulo, basta importá-lo:
import math
print(math.sqrt(16)) # 4.0
print(math.pi) # 3.141592653589793
Podemos importar apenas o que precisamos, ou dar um apelido com as:
from math import sqrt, pi # importa nomes específicos
import numpy as np # apelido, comum em bibliotecas
Criando o seu próprio módulo#
Qualquer arquivo .py seu também é um módulo. Suponha um arquivo saudacoes.py:
# saudacoes.py
def ola(nome):
return f"Olá, {nome}!"
PI = 3.14159
Em outro arquivo, na mesma pasta, você o importa pelo nome (sem o .py):
import saudacoes
print(saudacoes.ola("Arthur")) # Olá, Arthur!
O idioma if __name__ == "__main__"#
Quando um arquivo pode ser tanto executado diretamente quanto importado por outro, protegemos o código de teste com if __name__ == "__main__":. Esse bloco só roda quando o arquivo é executado diretamente, e não quando ele é importado:
# saudacoes.py
def ola(nome):
return f"Olá, {nome}!"
if __name__ == "__main__":
# Só executa ao rodar: python saudacoes.py
print(ola("mundo"))
Pacotes#
Um pacote é uma pasta que agrupa vários módulos relacionados. Na prática, é um diretório com arquivos .py (e, tradicionalmente, um arquivo __init__.py). Bibliotecas grandes como o NumPy e o Matplotlib são pacotes.
Instalando bibliotecas com o pip#
Nem tudo vem na biblioteca padrão. Milhares de bibliotecas de terceiros estão disponíveis no PyPI (Python Package Index) e são instaladas com o pip, o gerenciador de pacotes do Python. No terminal:
pip install requests
Depois de instalada, a biblioteca é usada como qualquer outra:
import requests
resposta = requests.get("https://api.github.com")
print(resposta.status_code) # 200
Dica - pip no Colab e no Jupyter
Dentro de um notebook (como o Google Colab), execute o pip em uma célula prefixada com !, assim: !pip install requests. O ! indica que a linha é um comando de terminal, e não código Python.
Ambientes virtuais (venv)#
Projetos diferentes podem precisar de versões diferentes da mesma biblioteca. Para evitar conflitos, criamos um ambiente virtual: uma instalação isolada do Python e das suas bibliotecas, separada por projeto. O módulo venv faz isso. No terminal:
# Cria o ambiente em uma pasta chamada .venv
python -m venv .venv
# Ativa o ambiente
source .venv/bin/activate # Linux e macOS
.venv\Scripts\activate # Windows
# Com o ambiente ativo, o pip instala apenas nele
pip install requests
# Ao terminar, desative
deactivate
Boa prática - um ambiente por projeto
Crie um ambiente virtual para cada projeto e evite instalar tudo no Python do sistema. Assim, as dependências de um projeto não interferem nas de outro, e fica fácil recriar o ambiente em outra máquina (por exemplo, listando as bibliotecas em um arquivo requirements.txt).
Uma alternativa moderna: o uv#
Nos últimos anos, o uv se popularizou como um substituto rápido para o pip e o venv. Escrito em Rust pela Astral, ele é muito mais veloz e reúne, em um só comando, a criação de ambientes e a instalação de pacotes.
Instalação (uma única vez, no sistema):
# Instalador oficial (Linux e macOS)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Ou, se você já tem o pip
pip install uv
No dia a dia, ele cria o ambiente e instala pacotes muito mais rápido que o pip:
# Cria o ambiente virtual (equivale ao python -m venv .venv)
uv venv
# Instala pacotes (interface compatível com o pip)
uv pip install requests
O uv também gerencia o projeto inteiro, controlando as dependências em um arquivo pyproject.toml:
uv init meu_projeto # cria a estrutura do projeto
cd meu_projeto
uv add requests # adiciona uma dependência (e atualiza o pyproject.toml)
uv run main.py # roda o script já dentro do ambiente do projeto
Dica - por que o uv?
O uv faz o papel de venv e pip (e mais) sendo dezenas de vezes mais rápido. Os comandos uv venv e uv pip install são quase idênticos aos que você já conhece, então a transição é simples. Hoje é a ferramenta recomendada para novos projetos.
Para saber mais
Documentação oficial do pip e do PyPI: https://pypi.org/. A lista completa de módulos da biblioteca padrão (que não precisam de instalação) está em https://docs.python.org/3/library/. Documentação do uv: https://docs.astral.sh/uv/.