Boas Práticas de Python Orientado a Objetos
Python não é Java - incline-se para objetos simples, funções e protocolos em vez de hierarquias de herança profundas. Estas regras mantêm o código OO Pythonic e testável.
Como Usar Esta Lista
- Aplique em revisões de design para novos modelos de domínio.
- Use ao refatorar "god-classes" ou "mixin soup".
- Emparelhe com protocolos mypy e Pydantic nas bordas do sistema.
- Releia após incidentes causados por estado de classe mutável compartilhado.
A - Modelagem
- Use
@dataclasspara registros de dados; adicione métodos apenas quando o comportamento for intrínseco. Nem tododictprecisa de uma classe. - Prefira composição (
tem-um) em vez de herança (é-um) além de um nível. Injete colaboradores em__init__. - Use
Enum/StrEnumem vez de constantes de string.matchexaustivo e prevenção de erros de digitação. - Modele dinheiro, IDs e quantidades como pequenos tipos de valor. Não
int/strcrus entre camadas. - Mantenha classes focadas - uma razão para mudar. Divida modelos de leitura de serviços de escrita quando necessário.
B - Herança e APIs
- Limite mixins a uma preocupação (logging, serialização). Documente o MRO ao usar múltiplos.
- Chame
super().__init__em cadeias de herança múltipla cooperativas. Cadeias quebradas pulam a inicialização. - Prefira
Protocolou ABC apenas quando múltiplas implementações existirem. YAGNI para implementação única. - Use fábricas
@classmethodpara construtores alternativos. Não padrões de__init__sobrecarregados. - API pública pequena; prefixe internos com
_. Propriedades expõem atributos estáveis sobre campos brutos.
C - Correção
- Alinhe
__eq__e__hash__para objetos de valor usados em conjuntos/dicionários. Ou usefrozen=Truedataclass. - Nunca mutate objetos congelados ou supostamente imutáveis. Campos de tupla dentro de dataclass ainda são mutáveis.
- Valide invariantes em
__post_init__ou setters. Falhe rapidamente na construção. - Retorne
NotImplementedde__eq__para tipos desconhecidos. Deixe o outro operando tentar a comparação reversa. - Evite atributos de classe mutáveis como padrões compartilhados. Defina por instância em
__init__.
D - Disciplina de Metaprogramação
- Opte por
__init_subclass__para hooks de registro. Não metaclasses personalizadas. - Alcance descritores/propriedades apenas quando validação ou cálculo preguiçoso se repetirem. Simples
__init__caso contrário. - Use
__slots__apenas com pressão de memória medida. Aceite restrições de herança. - Documente registros de plugins e limpe-os em testes. Evite poluição entre testes.
- Pule sobrecarga de operadores, a menos que o domínio seja naturalmente numérico/vetorial.
+surpreendente prejudica os leitores.
E - Testes e Limites
- Injete dependências (clock, storage, notifier) nos construtores. Não globais codificados.
- Implementações falsas para portas ABC/Protocol em testes unitários. Sem rede em testes de domínio.
- Use Pydantic 2 nas bordas HTTP; dataclasses simples internamente. Separação de transporte e domínio.
- Prefira funções para transformações sem estado entre objetos ricos. Métodos quando o comportamento pertence aos dados.
- Mantenha views Django/FastAPI finas - lógica de domínio em serviços testáveis.
FAQs
Quando a herança é aceitável?
Pontos de extensão de framework, mixins pequenos, polimorfismo de subtipo verdadeiro com poucos níveis.
dataclass vs modelo Pydantic?
dataclass no núcleo do domínio; Pydantic onde validação JSON/schema é necessária.
Todo arquivo deve ter classes?
Não - módulos de funções são Pythonic. Classes quando estado + comportamento se agrupam naturalmente.
Protocol ou ABC para portas?
Protocolo para tipos de terceiros estruturais; ABC quando você controla a herança e deseja guardas de instanciação.
Quantos métodos por classe?
Sem máximo fixo - se a classe rolar infinitamente, divida por responsabilidade ou extraia helpers.
privado com duplo underscore?
O mangling de __name é raro em código de aplicativo - a convenção de _ único é suficiente.
herdar de built-ins?
class MyDict(dict) com moderação - muitas vezes envolva ou componha em vez disso para APIs mais claras.
modelos ORM como domínio?
Mantenha linhas ORM anêmicas separadas do domínio rico quando a complexidade aumenta - camada anti-corrupção.
testando dataclasses?
Construa com campos mínimos; use replace() para variantes congeladas em testes.
maior "cheiro" OO em Python?
Herança profunda substituindo funções simples - refatore para composição e protocolos.
Relacionado
- Noções Básicas de OOP - exemplos introdutórios
- Herança e MRO - super e mixins
- Protocolos e Tipagem Estrutural - interfaces
- dataclasses - padrão de registro
Versões de Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.