Python

Módulos, Pacotes e Organização de Projetos Já leu

7 min de leitura

Módulos, Pacotes e Organização de Projetos
À medida que um programa cresce, colocar tudo em um único arquivo se torna insustentável. Módulos e pacotes são o mecanismo d

À 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:

  1. Verifica sys.modules — se já importado, usa o cache
  2. Busca o módulo na ordem: módulos embutidos → sys.path
  3. Carrega e executa o arquivo .py
  4. 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 nome ou import modulo as alias conforme 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.txt registra as dependências; pip install -r as reinstala
  • pyproject.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.
Comentários

Mais em Python

Strings em Profundidade: métodos, formatação e expressões regulares
Strings em Profundidade: métodos, formatação e expressões regulares

No artigo 02 vimos que strings s&atilde;o sequ&ecirc;ncias imut&aacute;veis d...

Dicionários: chave, valor e as estruturas do mundo real
Dicionários: chave, valor e as estruturas do mundo real

Se listas organizam dados por posi&ccedil;&atilde;o, dicion&aacute;rios organ...

Decoradores e Metaprogramação
Decoradores e Metaprogramação

Decoradores s&atilde;o um dos recursos mais elegantes do Python. Eles permite...