- Com a tendência recente do desenvolvimento de IA, começou a estudar e usar Python de forma séria, e agora sente grande satisfação com esse ecossistema
- Python evoluiu muito em relação ao passado e se tornou uma linguagem mais rápida e moderna, e ele percebe avanços significativos como os ganhos de desempenho com Cython
- Está adotando ativamente ferramentas e bibliotecas modernas de desenvolvimento como uv, ruff, pytest e Pydantic no seu fluxo de trabalho para aumentar a produtividade
- Também aplica estruturas de projeto e automação para reduzir a diferença entre ambientes de produção e o desenvolvimento baseado em notebooks/scripts Jupyter
- Usa GitHub Actions, Docker etc. para montar de forma eficiente CI/CD, testes e gerenciamento de infraestrutura
Resumo de I’m Switching to Python and Actually Liking It
Por que migrou para Python
- Em ambientes de desenvolvimento centrados em IA, Python se consolidou como a linguagem padrão de fato
- Antes era usado apenas para scripts simples, mas recentemente passou a utilizá-lo seriamente para criar “apps práticos” como RAG, agentes e IA generativa
- Nesse processo, percebeu que o ecossistema Python evoluiu muito em comparação com o passado
3 pontos fortes do Python
- Ecossistema rico de bibliotecas e ferramentas: especializado em processamento de dados, análise, web e IA
- Melhorias de desempenho com Cython e afins: possibilita otimização baseada em compilação
- Melhor legibilidade da sintaxe: sintaxes legadas como
__init__ e __new__ ficam ocultas, e a linguagem oferece uma sintaxe mais intuitiva
Estrutura do projeto (baseada em monorepo)
Principais ferramentas e configurações
-
uv
- Gerenciador moderno de pacotes Python e ferramenta de build fornecido pela Astral
- Executa rapidamente a maior parte das tarefas, como gerenciamento de dependências, criação de ambiente virtual e inicialização de projetos
pyproject.toml é o arquivo central de configuração, reunindo todos os metadados e as informações de dependências
- É possível configurar rapidamente o ambiente do projeto com os comandos
uv init, uv add e uv sync
-
ruff
- Linter Python ultrarrápido e formatador de código
- Ferramenta que integra
isort, flake8, autoflake etc.
- Faz lint e correções automáticas com
ruff check e ruff format
- Suporte nativo ao guia de estilo PEP 8
-
ty
- Verificador estático de tipos para Python criado pela Astral
- Em conjunto com
typing, é eficaz para análise estática e prevenção inicial de bugs
- Apesar de ainda estar em estágio inicial de desenvolvimento, já está em um nível utilizável com estabilidade
-
pytest
- Framework de testes Python mais representativo para testes unitários e ambientes de teste extensíveis
- Com regras simples de nome de arquivo e um único comando, já é possível integrar testes imediatamente
- Configure os testes como
test_*.py e execute com uv run pytest
- Sintaxe concisa e ecossistema rico de plugins
-
Pydantic
- Biblioteca para validação de dados e gerenciamento de configurações de ambiente
- Carregamento de configurações baseado em variáveis de ambiente
.env e validação de tipos
- Permite gerenciar com segurança chaves de API, URLs de banco de dados etc. por meio da classe
BaseSettings
-
MkDocs
- Dá suporte simples à geração de sites estáticos e documentação para projetos Python
- Permite aplicar rapidamente um design elegante no estilo de projetos open source
- Integração fácil com GitHub Pages
-
FastAPI
- Framework para criação rápida de APIs RESTful
- Vantagens como validação e documentação automáticas, alto desempenho e integração fácil com Pydantic
- Baseado em Starlette e Pydantic, oferece alta segurança de tipos e desempenho
-
Dataclasses
- Recurso padrão do Python que permite definir classes centradas em dados com facilidade
- Reduz fortemente boilerplate graças à geração automática de métodos especiais
Controle de versão e automação
-
GitHub Actions
- Configura pipelines de CI separados para
project-api e project-ui
- Oferece workflows ideais para construir pipelines de CI em vários sistemas operacionais
- Com ambiente de testes baseado em Docker, é possível testar no mesmo ambiente da produção
-
Dependabot
- Automatiza a atualização de dependências e o gerenciamento de patches de segurança
-
Gitleaks
- Ferramenta para evitar vazamento de informações sensíveis (senhas, chaves de API etc.), executando verificações de segurança antes dos commits no git
-
Pre-commit Hooks
- Ferramenta para lint, formatação e verificações de segurança automáticas antes do commit
- Usada com ruff, gitleaks etc. para manter consistência e qualidade do código
Automação de infraestrutura
-
Make
- Oferece um fluxo de desenvolvimento consistente com comandos como
make test e make infrastructure-up
- Há um Makefile na raiz do projeto e outro em
project-api
-
Docker & Docker Compose
project-api e project-ui são executados separadamente em contêineres
- Toda a aplicação pode ser iniciada com uma única linha:
docker compose up --build -d
- O
Dockerfile inclui a instalação do uv e o comando para executar a aplicação FastAPI
Encerrando
- Como mostrado acima, o ambiente moderno de desenvolvimento com Python permite montar um fluxo de trabalho de produção eficiente e robusto
- É possível aproveitar muitos benefícios do crescimento do ecossistema Python e da evolução das ferramentas em áreas como IA, dados e desenvolvimento web
- Dá para implementar uma cultura de desenvolvimento integrada, cobrindo estrutura de monorepo, ferramentas de automação, linter e verificador de tipos, ambiente de testes imediato, documentação e orquestração de infraestrutura
6 comentários
Estou migrando para Python e, sinceramente, estou gostando bastante.
Python tem a vantagem de contar com bibliotecas e frameworks abundantes, mas a desvantagem é que o gerenciamento de versões de pacotes não funciona tão bem e os conflitos são frequentes.
A tendência dos prós e contras é parecida com a do Java do passado.
O
uvmencionado no texto é realmente incrível. Além de ser muito rápido, também gerencia versões e dependências muito bem, meio no estilo do npm, então estou me estabelecendo com ouv.Mesmo assim, ultimamente parece que, com
uvepoetry, os conflitos e o gerenciamento de versões foram praticamente resolvidos na maior parte.Será que ele também é adequado para abranger o ecossistema, incluindo o React e esses tipos de partes?
Como a integração direta com React é difícil por serem linguagens diferentes, acho que algumas partes podem ser possíveis dependendo do que você deseja.
Pessoalmente, considero que o desenvolvimento de frontend com Python ainda não é uma área muito difundida.
Comentários no Hacker News
No código, quando faltam variáveis de ambiente, exibir uma mensagem com OR como “YOUTUBE_API_KEY ou YOUTUBE_CHANNEL_ID ausente” acaba irritando o usuário numa situação em que nem precisa usar OR. É muito melhor verificar cada valor separadamente e informar claramente qual está faltando. Como a diferença no tempo de desenvolvimento é quase nula, eu recomendo fazer assim
É um detalhe bem minucioso, mas acho que esse é um caso perfeito para usar o operador
:=(walrus). Por exemplo, dá para escrever direto algo comoif not (API_KEY := os.getenv("API_KEY")):. Pessoalmente, em ferramentas internas eu simplesmente deixoos.environ["API_KEY"]estourar umKeyError. Acho isso claro o suficiente tambémIndo além, acho muito melhor verificar as condições uma por uma e, se estiver faltando qualquer coisa, informar tudo de uma vez. Isso reduz o incômodo de rodar o programa por causa de uma variável ausente e depois descobrir outro erro de variável na sequência. Dependendo da situação, às vezes não dá para evitar esse incômodo, mas sempre que possível é melhor mostrar tudo de uma vez
O melhor é buscar todas as variáveis de ambiente e reportar de uma vez só quais estão faltando
Também dá para usar uma flag booleana e fazer um único
exit(1)no final. Assim você consegue mostrar todas as variáveis de ambiente ausentes de uma vezTambém é possível encerrar com código 1 já imprimindo a mensagem, como em
exit("Missing ...")Se você está procurando uma ferramenta para gerar automaticamente a estrutura do projeto, recomendo o cookiecutter. Tenho alguns templates que uso com frequência, como python-lib, click-app, datasette-plugin e llm-plugin. É só usar assim:
uvx cookiecutter gh:simonw/python-libEu fiz algo chamado baker em Ruby. O baker não copia um repositório de template; ele cria uma lista de tarefas a executar (uma lista de etapas em modo imperativo) e pode misturar tarefas manuais (como obter e configurar uma API key) com tarefas automáticas (como
uv init). Também dá para usar interpolação de strings do Ruby e bash na sintaxe Markdown. Acabei fazendo isso porque estava muito cansado de configs baseadas em ymlO que está em alta ultimamente é uma ferramenta chamada Copier. Veja a documentação do copier para mais detalhes
Eu até gosto de configurar projetos novos. Não tenho tanta vontade assim de automatizar isso
Na verdade, acho que esse tipo de ferramenta de automação estrutural combina perfeitamente com workflows modernos de desenvolvimento com LLMs baseados em agentes
A avaliação de que “Python é mais amigável para humanos porque já vem instalado por padrão na maioria dos Unix” é um pouco otimista. Passou de
import json, você cai rapidamente no inferno de virtualenv. Se quiser rodar em Python 3.13.x em Ubuntu 22.04 ou 24.04, Rocky 9 etc., no fimvenv, contêineres ou gerenciadores de versão acabam sendo obrigatóriosMesmo algo da biblioteca padrão como
import json, se fosse uma linguagem sem isso embutido, precisaria ser instalado à parte, mas o Python oferece alta produtividade no começo graças à biblioteca padrão. Claro que, em projetos grandes, a biblioteca padrão não basta, mas eu realmente já distribuí vários códigos de produção usando só a biblioteca padrão, sem problemas de deploy ou de gestão de segurança. Gerenciarvenvtambém não é mais tão difícil quanto antes, e os gerenciadores de pacotes evoluíramUma das minhas teorias meio em tom de piada é que metade do motivo de Docker/contêineres terem se espalhado tão rápido foi por ajudarem a superar o inferno de dependências do Python. Minha primeira experiência com Python foi instalar um serviço Python num servidor em 2012, e foi horrível: inferno de dependências, comandos de
venv, configuração de ambiente difícil de lidar. Fiquei apanhando compip,brewe ambiente macOS, e passei a evitar Python sempre que podia. Mas recentemente, por causa douv, sinto que Python melhorou bastante até para iniciantes. Sóuv init,uv addeuv runjá bastamAcho que sempre se deve usar virtualenv. No fim das contas é só um diretório e, hoje em dia, se você tentar instalar algo globalmente com
pip, ainda recebe aviso e tudo mais, então não é tão difícil quanto já foiÉ melhor mesmo usar virtualenv ou container. Mesmo que pareça difícil de lidar, isso evita afetar o sistema inteiro por causa de atualizações ou mudanças de versão de bibliotecas
Antigamente, era comum o sistema vir só com Python2 por padrão, e às vezes o próprio sistema dependia desse Python2, então isso era ainda mais perigoso
Tenho a sensação de que Python consegue ser ao mesmo tempo verboso e insuficiente. Para fazer algo simples, ou você acaba colocando umas 500 dependências, ou então o código cresce para dezenas, às vezes centenas de linhas até para tarefas muito triviais. Por isso evito Python: tem trabalho desnecessário demais. Prefiro Perl, porque consigo terminar muito mais rápido e de forma mais concisa. Com Python, muitas vezes parece programação pela programação, em vez de resolver o trabalho em si
Eu também faço muitos projetos sem dependências. Dá para fazer muita coisa de verdade só com a biblioteca padrão e um arquivo único. Se Python estiver instalado, dá até para baixar com
curle rodar direto. Por exemplo, tenho uma ferramenta CLI de controle de dinheiro com 2000 linhas, o plutus, que usa só umas 12 bibliotecas padrão. Cerca de 25% do código é só a parte de parse de comandos comargparse. Eu gosto de escrever de forma explícita, tipo uma linha por parâmetroVocê disse que Perl é mais rápido e poderoso que Python; fiquei curioso sobre quais exemplos concretos você tem em mente
No Python, é prático aninhar estruturas de dados sem precisar pensar muito. Você pode misturar livremente lista, tupla, dicionário etc. e acessar tudo com uma sintaxe consistente. Perl certamente é mais esperto e mais divertido, mas justamente por isso embaralha mais a minha cabeça, então não funciona tão bem para mim. Python é mais sem graça, mas a clareza é grande o suficiente para eu ainda entender o código daqui a 5 anos
Acho que Python é totalmente utilizável só com a biblioteca padrão
Eu gosto de monorepo, mas numa empresa em que trabalhei antes, essa abordagem acabou virando uma estrutura gigantesca e inchada, e ninguém queria mexer em nada com medo de tocar sem querer no código de outra equipe. O cerne do problema não era o repositório em si, e sim coisas como manter um único
requirements.txtpara o repositório inteiro ou scripts de build enrolados. Em teoria, bastaria atualizar dependências uma vez para que todo o código ficasse seguro com os patches mais recentes, mas na prática ninguém conseguia encostar nisso. Monorepo só funciona bem quando a organização tem uma cultura muito NIH (como o Google, de fazer tudo internamente). Por causa dessa experiência, passei a valorizar mais uma estrutura de microsserviços em que cada serviço corresponde à estrutura de equipes da organização. Vale ver também a Lei de ConwayPython é a linguagem que mais se aproxima de como eu escrevo pseudocódigo. Sempre que eu penso “isso está claro na minha cabeça”, o Python também tende a me oferecer uma abstração intuitiva para aquilo. Como venho de uma base mais matemática, isso me agradou bastante. Claro, hoje eu também gosto de outras linguagens, mas Python ainda tem seu charme
Eu monto meus projetos quase sempre com o mesmo padrão. É tão parecido que chega a ser assustador. Fico achando que o ecossistema de desenvolvedores Python está convergindo cada vez mais para um mesmo estilo. Antes eu achava que minhas escolhas eram únicas, mas vendo tanta gente fazer igual, dá vontade de perguntar para onde foi meu livre-arbítrio. Parece o fenômeno dos nomes de bebê: você acha que fez uma escolha original, mas na verdade escolheu o segundo nome mais popular
Esse tipo de estrutura já era popular em Python há uns 10 anos. No fim, parece que vários engenheiros racionais acabam convergindo naturalmente para esse padrão depois de pensar bastante
Tenho a sensação de que o ego humano está espalhado por todo o espectro como uma onda piloto quântica, e dali se transforma em existência. becoming-being, dá até risada
Fico feliz de ver mais gente passando a gostar de Python. Eu originalmente preferia Ruby, mas acabei tendo que usar Python por exigência de clientes. Antigamente Ruby era muito lento, mas, ao ser forçado a aprender Python, fui me acostumando aos poucos e hoje até gosto. Tenho algumas divergências sobre o uso de Make; se você não usa dependências de jeito nenhum, isso não é tão diferente assim de um script com
case... falando meio na brincadeira, mas dá uma tristeza ver que a geração atual não está tão acostumada com Make. Dá aquela sensação de “no meu tempo..."Ruby tem uma sintaxe muito mais bonita. Não curto essa ideia do Python de delimitar escopo só com indentação
Eu comecei com um script usando
casee, no fim, evoluí para umMakefilesimples.Makefileé mais padronizado e mais fácil de entender do que um script aleatórioEstou em dúvida entre usar Dataclass e Pydantic BaseModel. Se você já usa Pydantic, será que não faz sentido simplesmente padronizar tudo com Pydantic? Fico pensando se ainda existe motivo para usar Dataclass
O projeto attrs tem um texto comparativo muito bem organizado. Tem a comparação oficial do attrs; claro que há um pouco de viés, mas acho que os fundamentos são bem lógicos. E este blog também ajuda
Dataclass não oferece suporte à validação de objetos aninhados. Então, para estruturas simples e planas usadas para passar argumentos entre funções, é melhor usar dataclass. É mais claro do que ficar recebendo um monte de argumentos demais em lista
Existe uma questão de queda de desempenho por causa da validação dos dados na criação. Há alternativas bem mais leves e rápidas, como
msgspecSe você não precisa de validação nem serialização, então Pydantic acaba sendo overhead desnecessário. Minha regra é: se precisa de serialização, Pydantic; se não, dataclass
Dá para usar uma dataclass existente direto com algo como
TypeAdapter(MyDataclass), então fico pensando se realmente há motivo para criar um modelo Pydantic separadoUltimamente, na verdade, tenho estado mais satisfeito migrando para outras linguagens em vez de Python. Organizei meus pensamentos sobre Python neste texto. Se eu tiver chance de usar Python de novo no futuro, quero com certeza experimentar
uv,ruffetyasync. Python temasyncio, mas há várias abordagens concorrentes coexistindo e nunca se consolidou um padrão. No JS, isso ficou concentrado em uma coisa só, o que foi muito mais confortável para mim. Somando também vários detalhes pequenos, a diferença ficou grande: em Python, escopo por indentação, problemas de caminho relativo em imports; no JS, a sintaxe de objetos etc. me parece mais agradável. Veja esta explicação relacionada