Como organizar código Python: imports, módulos e boas práticas
Saia do 'tudo num arquivo só' e aprenda a organizar seu código Python com módulos, imports e boas práticas de escrita.
O problema do arquivo gigante
No começo, é normal colocar tudo num arquivo só. Mas conforme o projeto cresce, isso vira um pesadelo:
# app.py - 800 linhas, tudo misturado
def conectar_banco():
...
def validar_email():
...
def calcular_frete():
...
def enviar_notificacao():
...
# mais 50 funcoes aqui...
Você não encontra nada, funções não relacionadas ficam juntas e qualquer mudança vira um risco. A solução é separar em módulos.
Módulos: cada arquivo é um módulo
Em Python, qualquer arquivo .py é um módulo. Você pode importar funções de um arquivo em outro:
meu_projeto/
app.py
validacao.py
banco.py
# validacao.py
def email_valido(email):
return "@" in email and "." in email
def cpf_valido(cpf):
return len(cpf) == 11 and cpf.isdigit()
# app.py
from validacao import email_valido, cpf_valido
email = input("Email: ")
if email_valido(email):
print("Email valido!")
Cada arquivo tem uma responsabilidade clara. Se precisar mexer na validação, você sabe exatamente onde ir.
Formas de importar
import simples
import validacao
validacao.email_valido("teste@email.com")
Usa o nome do módulo como prefixo. Bom para evitar conflitos de nomes.
from ... import
from validacao import email_valido
email_valido("teste@email.com")
Importa direto, sem prefixo. Mais prático quando você usa poucas funções.
import com apelido
import validacao as val
val.email_valido("teste@email.com")
Útil quando o nome do módulo é longo.
Evite import com asterisco
from validacao import * # NAO faca isso
Importa tudo de uma vez. Parece conveniente, mas você perde o controle sobre o que está usando e pode sobrescrever funções sem perceber.
Pacotes: organizando em pastas
Quando o projeto cresce, agrupe módulos em pastas. Uma pasta com um arquivo __init__.py (pode estar vazio) é um pacote:
meu_projeto/
app.py
utils/
__init__.py
validacao.py
formatacao.py
banco/
__init__.py
conexao.py
consultas.py
# app.py
from utils.validacao import email_valido
from banco.conexao import conectar
Cada pasta agrupa módulos relacionados. A estrutura do projeto já conta a história do que ele faz.
O que é __name__ == "__main__"
Você vai encontrar isso em muitos projetos Python:
# calculadora.py
def somar(a, b):
return a + b
def subtrair(a, b):
return a - b
if __name__ == "__main__":
print(somar(10, 5))
print(subtrair(10, 5))
Como funciona
Quando você roda python calculadora.py direto, o Python define __name__ como "__main__". O bloco if executa.
Quando outro arquivo importa esse módulo, __name__ é "calculadora". O bloco if não executa.
# app.py
from calculadora import somar
print(somar(3, 7)) # funciona, sem executar os prints do if
Use isso para separar o código que define funções do código que as testa. É uma boa prática em qualquer módulo.
Nomeação: a PEP 8
A PEP 8 é o guia de estilo oficial do Python. Você não precisa decorar tudo, mas essas regras são essenciais:
Variáveis e funções: snake_case
# Certo
nome_completo = "Maria Silva"
def calcular_total(itens):
...
# Errado
NomeCompleto = "Maria Silva"
def CalcularTotal(itens):
...
Classes: PascalCase
# Certo
class ContaBancaria:
...
# Errado
class conta_bancaria:
...
Constantes: MAIUSCULAS_COM_UNDERSCORE
# Certo
TAXA_JUROS = 0.05
MAX_TENTATIVAS = 3
# Errado
taxa_juros = 0.05
Nomes significativos
# Ruim - o que e x, y, d?
def calc(x, y, d):
return x * y * (1 - d)
# Bom - qualquer pessoa entende
def calcular_preco(quantidade, preco_unitario, desconto):
return quantidade * preco_unitario * (1 - desconto)
O nome deve dizer o que a coisa é ou faz, sem precisar de comentário.
Funções pequenas e focadas
Cada função deve fazer uma coisa e fazer bem:
# Ruim - faz tudo junto
def processar_pedido(pedido):
# valida
if not pedido["email"]:
return "Email obrigatorio"
if pedido["total"] <= 0:
return "Total invalido"
# calcula
subtotal = sum(item["preco"] for item in pedido["itens"])
frete = 15.0 if subtotal < 100 else 0
total = subtotal + frete
# salva no banco
db.insert({"pedido": pedido, "total": total})
# envia email
enviar_email(pedido["email"], f"Pedido confirmado: R$ {total}")
return "OK"
# Bom - cada funcao com sua responsabilidade
def validar_pedido(pedido):
if not pedido["email"]:
raise ValueError("Email obrigatorio")
if pedido["total"] <= 0:
raise ValueError("Total invalido")
def calcular_total(itens):
subtotal = sum(item["preco"] for item in itens)
frete = 15.0 if subtotal < 100 else 0
return subtotal + frete
def processar_pedido(pedido):
validar_pedido(pedido)
total = calcular_total(pedido["itens"])
db.insert({"pedido": pedido, "total": total})
enviar_email(pedido["email"], f"Pedido confirmado: R$ {total}")
Funções menores são mais fáceis de entender, testar e reutilizar.
Comentários: menos é mais
Comentários bons explicam o porquê
# Timeout maior porque a API do banco e lenta nos horarios de pico
resposta = requests.get(url, timeout=30)
# Ignora o primeiro elemento que e sempre o cabecalho
dados = linhas[1:]
Comentários ruins explicam o óbvio
# Incrementa o contador
contador += 1
# Retorna o nome
return nome
# Cria uma lista vazia
itens = []
Se o código está tão confuso que precisa de comentário para cada linha, o problema não é a falta de comentário — é o código.
Código legível > comentário
# Com comentario para compensar nome ruim
x = 0.05 # taxa de juros
# Sem comentario, nome auto-explicativo
taxa_juros = 0.05
Estrutura de um projeto real
Para projetos pequenos a médios, essa estrutura funciona bem:
meu_projeto/
app.py ← ponto de entrada
config.py ← configuracoes (constantes, variaveis de ambiente)
models/
__init__.py
usuario.py ← logica de usuario
produto.py ← logica de produto
utils/
__init__.py
validacao.py ← funcoes de validacao
formatacao.py ← funcoes de formatacao
requirements.txt ← dependencias
.gitignore ← arquivos ignorados pelo Git
.env ← variaveis de ambiente (nunca vai pro Git)
Dicas para organizar
| Regra | Exemplo |
|---|---|
| Agrupe por funcionalidade | models/, utils/, routes/ |
| Um módulo = uma responsabilidade | validacao.py só valida |
| Configurações separadas | config.py com constantes e variáveis de ambiente |
| Ponto de entrada claro | app.py ou main.py na raiz |
| Segredos fora do código | .env para tokens e senhas |
Ordem dos imports
A PEP 8 recomenda organizar os imports em três grupos, separados por uma linha em branco:
# 1. Biblioteca padrao do Python
import os
import json
from datetime import datetime
# 2. Bibliotecas externas (instaladas com pip)
import requests
from flask import Flask
# 3. Modulos do seu projeto
from utils.validacao import email_valido
from models.usuario import criar_usuario
Manter essa ordem facilita saber de onde cada coisa vem.
Resumo
| Conceito | Regra |
|---|---|
| Módulos | Cada arquivo .py é um módulo |
| Pacotes | Pasta com __init__.py |
| Imports | Prefira from ... import específico |
__name__ |
Use para separar definições de execução |
| Nomeação | snake_case para variáveis/funções, PascalCase para classes |
| Funções | Pequenas, focadas, uma responsabilidade |
| Comentários | Explique o porquê, não o quê |
| Estrutura | Agrupe por funcionalidade, configure separado |
Organizar código não é frescura — é o que separa um script de estudante de um projeto profissional. Comece aplicando essas práticas agora e seu código vai ser mais fácil de ler, manter e evoluir.