À medida que um programa cresce, colocar tudo em um único arquivo se torna insustentável. Módulos e pacotes são o mecanismo do Python para dividir código em unidades organizadas, reutilizáveis e independentes. Entender como o Python resolve importações e como estruturar um projeto profissional é essencial para qualquer desenvolvedor que queira além de scripts simples.
O que é um Módulo?
Um módulo é simplesmente um arquivo .py. Qualquer arquivo Python é automaticamente um módulo e pode ser importado por outros arquivos.
# arquivo: matematica.py
PI = 3.14159265358979
def area_circulo(raio):
"""Calcula a área de um círculo."""
return PI * raio ** 2
def area_retangulo(largura, altura):
"""Calcula a área de um retângulo."""
return largura * altura
def mdc(a, b):
"""Máximo divisor comum — algoritmo de Euclides."""
while b:
a, b = b, a % b
return a
# arquivo: main.py
import matematica
print(matematica.PI)
print(matematica.area_circulo(5))
print(matematica.mdc(48, 18))
Formas de Importação
# Importa o módulo inteiro — acesso via nome do módulo
import matematica
print(matematica.PI)
# Importa com alias — útil para nomes longos
import matematica as mat
print(mat.area_circulo(3))
# Importa nomes específicos — acesso direto
from matematica import PI, area_circulo
print(PI)
print(area_circulo(3))
# Importa tudo — evite, polui o namespace
from matematica import *
# Módulos da biblioteca padrão
import os
import sys
import json
from datetime import datetime, timedelta
from pathlib import Path
from collections import defaultdict, Counter
O Atributo name
Cada módulo tem um atributo __name__. Quando executado diretamente, vale "__main__"; quando importado, vale o nome do arquivo:
# arquivo: utilitarios.py
def somar(a, b):
return a + b
def subtrair(a, b):
return a - b
if __name__ == "__main__":
# Este bloco só executa quando o arquivo é rodado diretamente
# Não executa quando o módulo é importado
print("Testando utilitarios.py")
print(somar(3, 4)) # 7
print(subtrair(10, 3)) # 7
Esse padrão é fundamental — permite que um arquivo funcione tanto como módulo reutilizável quanto como script independente.
Pacotes
Um pacote é um diretório que contém módulos e um arquivo especial __init__.py. Esse arquivo pode estar vazio ou conter código de inicialização do pacote.
meu_projeto/
├── __init__.py
├── matematica/
│ ├── __init__.py
│ ├── basica.py
│ ├── geometria.py
│ └── estatistica.py
├── utils/
│ ├── __init__.py
│ ├── arquivos.py
│ └── strings.py
└── main.py
# matematica/geometria.py
def area_circulo(raio):
import math
return math.pi * raio ** 2
def volume_esfera(raio):
import math
return (4/3) * math.pi * raio ** 3
# matematica/__init__.py
from .basica import somar, subtrair, mdc
from .geometria import area_circulo, volume_esfera
__all__ = ["somar", "subtrair", "mdc", "area_circulo", "volume_esfera"]
# main.py
from matematica import area_circulo, somar
from matematica.geometria import volume_esfera
print(area_circulo(5))
print(volume_esfera(3))
print(somar(2, 3))
Importações Relativas
Dentro de um pacote, use importações relativas para referenciar módulos do mesmo pacote:
# matematica/estatistica.py
from .basica import somar # importa do mesmo pacote
from ..utils.strings import formatar # importa do pacote pai
def media(valores):
return somar(*valores) / len(valores)
. refere-se ao pacote atual; .. refere-se ao pacote pai.
Ambiente Virtual
Antes de instalar dependências externas, crie sempre um ambiente virtual — um espaço isolado que mantém as dependências de cada projeto separadas:
# Criar ambiente virtual
python3 -m venv venv
# Ativar — Linux/macOS
source venv/bin/activate
# Ativar — Windows
venv\Scripts\activate
# Desativar
deactivate
Com o ambiente ativo, instale pacotes com pip:
pip install requests
pip install pandas numpy matplotlib
pip install fastapi uvicorn
Gerenciamento de Dependências
# Gerar arquivo de dependências
pip freeze > requirements.txt
# Instalar dependências de um arquivo
pip install -r requirements.txt
# Ver pacotes instalados
pip list
# Informações sobre um pacote
pip show requests
Conteúdo típico de requirements.txt:
requests==2.31.0
pandas==2.1.0
numpy==1.26.0
fastapi==0.104.0
uvicorn==0.24.0
Estrutura de Projeto Profissional
Uma estrutura bem organizada facilita testes, manutenção e colaboração:
meu_projeto/
├── src/
│ └── meu_projeto/
│ ├── __init__.py
│ ├── modelos/
│ │ ├── __init__.py
│ │ ├── usuario.py
│ │ └── produto.py
│ ├── servicos/
│ │ ├── __init__.py
│ │ ├── autenticacao.py
│ │ └── email.py
│ ├── repositorios/
│ │ ├── __init__.py
│ │ └── usuario_repo.py
│ └── utils/
│ ├── __init__.py
│ └── validacao.py
├── tests/
│ ├── __init__.py
│ ├── test_modelos.py
│ └── test_servicos.py
├── docs/
├── .env
├── .gitignore
├── pyproject.toml
├── requirements.txt
└── README.md
pyproject.toml
O arquivo moderno de configuração de projetos Python, substituindo o antigo setup.py:
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.backends.legacy:build"
[project]
name = "meu-projeto"
version = "0.1.0"
description = "Descrição do projeto"
requires-python = ">=3.11"
dependencies = [
"requests>=2.31.0",
"fastapi>=0.104.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"black>=23.0.0",
"ruff>=0.1.0",
]
[tool.black]
line-length = 88
[tool.ruff]
line-length = 88
select = ["E", "F", "I"]
O Sistema de Importação por Dentro
Quando você escreve import matematica, Python executa os seguintes passos:
- Verifica
sys.modules— se já importado, usa o cache - Busca o módulo na ordem: módulos embutidos →
sys.path - Carrega e executa o arquivo
.py - Armazena em
sys.modules
import sys
# Ver onde Python busca módulos
for caminho in sys.path:
print(caminho)
# Ver módulos já importados
print("json" in sys.modules) # True se json foi importado
# Adicionar caminho dinamicamente (evite em produção)
sys.path.insert(0, "/caminho/para/meus/modulos")
Exemplo Completo: Pacote de Utilitários
# utils/validacao.py
import re
from dataclasses import dataclass
from typing import List
@dataclass
class ResultadoValidacao:
valido: bool
erros: List[str]
def __bool__(self):
return self.valido
def validar_email(email: str) -> ResultadoValidacao:
erros = []
if not email:
erros.append("E-mail não pode ser vazio.")
elif not re.match(r"^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$", email):
erros.append("Formato de e-mail inválido.")
return ResultadoValidacao(valido=not erros, erros=erros)
def validar_senha(senha: str) -> ResultadoValidacao:
erros = []
if len(senha) < 8:
erros.append("Senha deve ter ao menos 8 caracteres.")
if not re.search(r"[A-Z]", senha):
erros.append("Senha deve conter ao menos uma letra maiúscula.")
if not re.search(r"\d", senha):
erros.append("Senha deve conter ao menos um número.")
if not re.search(r"[!@#$%^&*]", senha):
erros.append("Senha deve conter ao menos um caractere especial.")
return ResultadoValidacao(valido=not erros, erros=erros)
def validar_cadastro(dados: dict) -> ResultadoValidacao:
todos_erros = []
email_result = validar_email(dados.get("email", ""))
if not email_result:
todos_erros.extend(email_result.erros)
senha_result = validar_senha(dados.get("senha", ""))
if not senha_result:
todos_erros.extend(senha_result.erros)
return ResultadoValidacao(valido=not todos_erros, erros=todos_erros)
# utils/__init__.py expõe a interface pública do pacote
# from .validacao import validar_email, validar_senha, validar_cadastro
# main.py
from utils.validacao import validar_cadastro
cadastros = [
{"email": "ana@email.com", "senha": "Segura@123"},
{"email": "invalido", "senha": "fraca"},
{"email": "bruno@email.com","senha": "SemEspecial1"},
]
for dados in cadastros:
resultado = validar_cadastro(dados)
if resultado:
print(f"[OK] {dados['email']} — cadastro válido")
else:
print(f"[ERRO] {dados['email']}:")
for erro in resultado.erros:
print(f" - {erro}")
Resumo
- Um módulo é qualquer arquivo
.py; um pacote é um diretório com__init__.py - Use
import modulo,from modulo import nomeouimport modulo as aliasconforme a necessidade - O padrão
if __name__ == "__main__"separa execução direta de importação - Ambientes virtuais isolam dependências por projeto — sempre use um
pip freeze > requirements.txtregistra as dependências;pip install -ras reinstalapyproject.tomlé o padrão moderno de configuração de projetos Python- Importações relativas (
.e..) referenciam módulos dentro do mesmo pacote - Uma boa estrutura de projeto separa modelos, serviços, repositórios e utilitários desde o início
Referências e Leituras Complementares
- Sistema de importação — documentação oficial — https://docs.python.org/3/reference/import.html
- Ambientes virtuais e pip — https://docs.python.org/3/tutorial/venv.html
- pyproject.toml — PEP 517 e 518 — https://peps.python.org/pep-0517/
- Guia de empacotamento Python — https://packaging.python.org/en/latest/
- BEAZLEY, David; JONES, Brian K. Python Cookbook. 3. ed. O'Reilly Media, 2013. Cap. 10 — módulos e pacotes em profundidade.
- HUNT, John. Advanced Guide to Python 3 Programming. Springer, 2019. Cap. 2 — estrutura de projetos e boas práticas.
- PERCIVAL, Harry; GREGORY, Bob. Architecture Patterns with Python. O'Reilly Media, 2020. Cap. 1 — organização de projetos orientados a domínio.