Escrever Python que roda é fácil. Escrever Python que outra pessoa — ou você daqui a seis meses — consiga ler, mudar e confiar é outra história. E quase nada disso vem de truques da linguagem: vem de hábitos simples repetidos com disciplina.

Nomes que dizem o que fazem
Nome bom é a única documentação que nunca fica desatualizada. d não diz nada; dias_em_atraso diz. process() é vago; enviar_cobranca() conta a história. Quando você precisa de um comentário só pra explicar o que uma variável guarda, geralmente o nome é que está errado.
Reserve nomes curtos para escopos curtos — o i de um for de três linhas está ótimo. Fora isso, prefira clareza a economia de teclas. Ninguém nunca reclamou que um nome era legível demais.
Funções que fazem uma coisa só

Uma função que valida o formulário, grava no banco e ainda dispara o e-mail de confirmação é, na verdade, três funções fingindo ser uma. No dia em que você quiser testar só a validação, vai ter que subir banco e servidor de e-mail junto. Separe.
O teste prático é o nome: se pra descrever a função você usa um "e" ("valida e salva e notifica"), ela provavelmente faz coisas demais. Funções pequenas e focadas são mais fáceis de ler, testar e reaproveitar — e o código de cima, que só chama uma atrás da outra, vira quase um resumo do que acontece.
Não abstraia cedo demais
Existe uma vontade quase irresistível de, ao ver dois trechos parecidos, criar já uma função genial que resolve os dois. Segure. Duplicação é barata e visível; a abstração errada é cara e gruda. Uma função com sete parâmetros e três flags booleanas quase sempre nasceu de uma generalização apressada.
A regra prática é esperar o padrão se repetir uma terceira vez antes de extrair. Aí você já viu variação suficiente pra saber o que de fato é comum. Abstraia o que se provou estável, não o que você imagina que talvez um dia mude.
Isole o ambiente e trave as dependências

"Na minha máquina funciona" quase sempre é uma história sobre dependências. Um ambiente virtual por projeto (python -m venv .venv) impede que a biblioteca de um projeto contamine outro, e mantém o seu Python global limpo.
Mais importante: trave as versões. Um requirements.txt com versões fixas, ou uma ferramenta com arquivo de lock, garante que quem clonar o repositório amanhã instale exatamente o que você testou hoje. Dependência sem versão travada é uma atualização silenciosa esperando pra quebrar o build no pior momento.
Type hints onde ajudam de verdade
Type hints não deixam o Python mais rápido, mas deixam o seu editor e os seus colegas muito mais espertos. Anote onde o ganho é maior: as fronteiras públicas — assinaturas de funções e valores de retorno. def calcular_total(itens: list[Item]) -> Decimal: já diz mais que um parágrafo de docstring.
Rode um checador como o mypy no CI pra que essas anotações sejam verificadas de verdade, e não virem enfeite. Mas não caia no exagero de tipar cada variável local óbvia — hint é ferramenta de comunicação, não imposto. Onde não esclarece, atrapalha.
Erros explícitos e testes como hábito
Um except Exception: pass é onde os bugs vão morar de graça. Capture a exceção específica que você sabe tratar e deixe o resto estourar — um erro barulhento no lugar certo é infinitamente melhor que um sistema que falha em silêncio. Prefira falhar cedo a mascarar o problema.
E testes não são uma fase depois do código; são parte de escrevê-lo. Não precisa mirar 100% de cobertura no primeiro dia — comece pelos casos de borda e pelos caminhos que, se quebrarem, doem. Um punhado de testes bons compra algo que nenhuma quantidade de cuidado manual dá: coragem pra refatorar.
Código limpo não é vaidade nem perfeccionismo. É o que permite mudar rápido, sem medo, quando o requisito muda — e ele sempre muda. Comece por um hábito, aplique no próximo commit, e deixe o resto vir junto.

