Caminhos com pathlib
Esta aula explora a biblioteca pathlib do Python, que oferece uma API orientada a objetos para manipular caminhos de arquivos. Você aprenderá sobre a classe Path, suas principais operações, comparações com os.path e boas práticas para escrever código mais limpo e portável.
A manipulação de caminhos de arquivos é uma tarefa comum em qualquer programa Python. Tradicionalmente, usávamos funções como os.path.join e os.path.exists para lidar com strings de caminho. No entanto, desde o Python 3.4, a biblioteca pathlib oferece uma abordagem mais moderna e orientada a objetos, tornando o código mais legível e menos propenso a erros. Nesta aula, vamos mergulhar fundo em pathlib, explorando sua classe principal Path, as operações mais úteis, comparações com os.path e boas práticas para adotá-la em seus projetos.
O pathlib trata caminhos como objetos, permitindo que você realize operações como concatenação, verificação de existência e leitura de arquivos de forma intuitiva. Ele também é multiplataforma, lidando automaticamente com as diferenças entre sistemas operacionais (como barras em Windows e Linux). Vamos começar entendendo a classe Path.
Path
A classe Path é o coração do pathlib. Ela representa um caminho de arquivo ou diretório, independente do sistema operacional. Você pode criar uma instância de Path passando uma string com o caminho, ou usando métodos de classe como Path.cwd() e Path.home(). Uma vez criado, o objeto Path fornece diversos atributos e métodos para trabalhar com o caminho.
Um dos grandes benefícios é a sobrecarga de operadores: você pode usar / para unir caminhos, o que é muito mais elegante que os.path.join. Além disso, o objeto Path é imutável e hashable, o que o torna seguro para uso em dicionários e conjuntos.
from pathlib import Path
# Criando objetos Path
caminho = Path("meu_projeto/arquivo.txt")
print(caminho) # meu_projeto/arquivo.txt
# Caminho absoluto
absoluto = Path.cwd() / "meu_projeto" / "arquivo.txt"
print(absoluto) # /home/usuario/meu_projeto/arquivo.txt
# Diretório home
home = Path.home()
print(home) # /home/usuario ou C:\Users\usuario
# Atributos do caminho
print(caminho.name) # arquivo.txt
print(caminho.stem) # arquivo
print(caminho.suffix) # .txt
print(caminho.parent) # meu_projeto
print(caminho.anchor) # '' (vazio para relativo) ou '/' no Unix
Além dos atributos básicos, Path oferece métodos para verificar propriedades do caminho, como exists(), is_file(), is_dir(), e para manipular o sistema de arquivos, como mkdir(), rename(), unlink(). Veremos esses métodos em detalhes na próxima seção.
Operações
O pathlib fornece uma vasta gama de operações para trabalhar com arquivos e diretórios. Vamos dividir em categorias: operações de consulta, operações de modificação e operações de iteração.
Operações de consulta
Essas operações nos permitem obter informações sobre o caminho sem alterá-lo.
exists(): verifica se o caminho existe.is_file()eis_dir(): verificam se é um arquivo ou diretório.stat(): retorna informações detalhadas como tamanho, permissões, etc.resolve(): retorna o caminho absoluto, resolvendo links simbólicos.iterdir(): gera os itens de um diretório.
from pathlib import Path
caminho = Path("meu_projeto/arquivo.txt")
# Verificação de existência
print(caminho.exists()) # False (se não existir)
# Criando um diretório e arquivo para teste
Path("meu_projeto").mkdir(exist_ok=True)
Path("meu_projeto/arquivo.txt").touch()
print(caminho.exists()) # True
print(caminho.is_file()) # True
print(caminho.is_dir()) # False
# Resolver caminho absoluto
print(caminho.resolve()) # /home/usuario/meu_projeto/arquivo.txt
# Iterar sobre diretório
for item in Path("meu_projeto").iterdir():
print(item)
Operações de modificação
Essas operações alteram o sistema de arquivos.
mkdir(): cria um diretório.rename(): renomeia um arquivo ou diretório.unlink(): remove um arquivo.rmdir(): remove um diretório vazio.touch(): cria um arquivo vazio ou atualiza a data de modificação.write_text()eread_text(): escrever e ler texto de forma simples.
from pathlib import Path
caminho = Path("meu_projeto/arquivo.txt")
# Escrever texto
caminho.write_text("Olá, mundo!", encoding="utf-8")
# Ler texto
print(caminho.read_text(encoding="utf-8")) # Olá, mundo!
# Renomear
caminho.rename("meu_projeto/renomeado.txt")
# Remover arquivo
caminho.unlink()
# Criar e remover diretório
Path("meu_projeto/temp").mkdir()
Path("meu_projeto/temp").rmdir()
Operações de iteração e busca
O método glob() é extremamente útil para encontrar arquivos que correspondem a um padrão, semelhante ao glob do módulo glob, mas integrado ao Path.
from pathlib import Path
# Listar todos os arquivos .txt em um diretório
for txt in Path("meu_projeto").glob("*.txt"):
print(txt)
# Recursivamente
for py in Path("meu_projeto").rglob("*.py"):
print(py)
vs os.path
Antes do pathlib, a manipulação de caminhos era feita principalmente com o módulo os.path, que trata caminhos como strings. Enquanto os.path é funcional, ele tem algumas desvantagens: requer cuidado com separadores, concatenação manual e não é tão expressivo. Vamos comparar as duas abordagens.
Com os.path, você precisa usar funções como os.path.join para concatenar, os.path.exists para verificar existência, e os.path.isdir para checar diretórios. Tudo isso retorna strings, o que pode levar a erros sutis. Já com pathlib, você tem objetos com métodos, tornando o código mais orientado a objetos e fácil de ler.
| Operação | os.path | pathlib |
|---|---|---|
| Concatenar | os.path.join("dir", "file") | Path("dir") / "file" |
| Existência | os.path.exists(path) | Path(path).exists() |
| Nome do arquivo | os.path.basename(path) | Path(path).name |
| Extensão | os.path.splitext(path)[1] | Path(path).suffix |
| Diretório pai | os.path.dirname(path) | Path(path).parent |
Além disso, pathlib é mais seguro em relação a diferenças entre sistemas operacionais: enquanto os.path.join usa o separador correto automaticamente, pathlib também o faz, mas de forma mais transparente. O pathlib também oferece métodos convenientes para operações de arquivo, como read_text() e write_text(), que exigiriam abrir o arquivo manualmente com open() no estilo os.path.
No entanto, o os.path ainda é amplamente utilizado em código legado e em algumas APIs que esperam strings. O pathlib é recomendado para novos projetos, e o Python 3.6+ integrou pathlib como padrão para muitas funções (por exemplo, open() aceita objetos Path).
Boas práticas
Ao usar pathlib, algumas boas práticas podem tornar seu código mais robusto e legível.
- Use
Pathem vez de strings: Sempre que possível, prefira objetosPatha strings para representar caminhos. Isso evita erros de concatenação e facilita a leitura. - Aproveite o operador
/: Use/para unir caminhos, em vez deos.path.joinou f-strings com barras. Isso torna o código mais limpo e portável. - Utilize métodos de conveniência: Para ler e escrever arquivos, use
read_text()ewrite_text()em vez de abrir manualmente comopen()quando o conteúdo for texto simples. Eles gerenciam o fechamento do arquivo automaticamente. - Prefira
glob()para buscar arquivos: UsePath.glob()erglob()para listar arquivos, em vez de combinaros.listdir()comfnmatch. - Trate erros adequadamente: Ao realizar operações que podem falhar (como
mkdir()ouunlink()), capture exceções comoFileExistsErroreFileNotFoundError.
from pathlib import Path
import shutil
# Exemplo de boas práticas
def criar_projeto(nome: str):
"""Cria um diretório de projeto com um README."""
projeto = Path("projetos") / nome
try:
projeto.mkdir(parents=True, exist_ok=False)
except FileExistsError:
raise ValueError(f"Projeto {nome} já existe.")
readme = projeto / "README.md"
readme.write_text(f"# {nome}\n", encoding="utf-8")
return projeto
# Uso
projeto = criar_projeto("meu_app")
print(projeto)
Referências
- Documentação oficial do pathlib
- Documentação do os.path
- Python's pathlib: How to Use Paths with Modern Python (Real Python)
- PEP 428 – The pathlib module
- pathlib module in Python (GeeksforGeeks)
- Pathlib in Python (TutorialsPoint)
Exercícios
- Exercício 1: Crie um script que use
pathlibpara listar todos os arquivos com extensão.pyno diretório atual e em subdiretórios, e imprima o nome e o tamanho de cada um.
from pathlib import Path
for py in Path('.').rglob('*.py'):
if py.is_file():
print(f'{py}: {py.stat().st_size} bytes')
- Exercício 2: Escreva uma função que, dado um diretório, crie uma subpasta chamada
backupe copie todos os arquivos.txtdo diretório original para ela, mantendo os nomes.
import shutil
from pathlib import Path
def backup_txt(diretorio):
dir_path = Path(diretorio)
backup_dir = dir_path / 'backup'
backup_dir.mkdir(exist_ok=True)
for txt in dir_path.glob('*.txt'):
shutil.copy2(txt, backup_dir / txt.name)
- Exercício 3: Usando
pathlib, verifique se um caminho é absoluto ou relativo. Se for relativo, converta para absoluto usandoresolve()e imprima o resultado.
from pathlib import Path
caminho = Path('algum/arquivo.txt')
if caminho.is_absolute():
print('Absoluto')
else:
print('Relativo')
print('Absoluto:', caminho.resolve())
- Exercício 4: Crie uma função que receba um caminho de arquivo e retorne o diretório pai, o nome do arquivo sem extensão e a extensão, usando
pathlib.
from pathlib import Path
def info_arquivo(caminho):
p = Path(caminho)
return {
'pai': p.parent,
'nome_sem_ext': p.stem,
'extensao': p.suffix
}
- Exercício 5: Escreva um script que percorra um diretório e, para cada arquivo que tenha mais de 1 MB, imprima seu caminho e tamanho em MB.
from pathlib import Path
for arquivo in Path('.').rglob('*'):
if arquivo.is_file():
tamanho = arquivo.stat().st_size
if tamanho > 1_000_000:
print(f'{arquivo}: {tamanho/1_000_000:.2f} MB')
Observações finais
O pathlib é uma adição moderna e poderosa à biblioteca padrão do Python. Ele simplifica o trabalho com caminhos, tornando o código mais limpo e menos propenso a erros. Ao migrar de os.path, você notará uma curva de aprendizado suave, mas os benefícios em legibilidade e segurança valem a pena. Lembre-se de que, para muitas funções que aceitam strings de caminho, você pode passar diretamente um objeto Path (por exemplo, open(), shutil.copy()), o que facilita a integração. Pratique com os exercícios e explore a documentação oficial para descobrir todos os recursos disponíveis.