Herança dá à subclasse tudo, inclusive o que ela não deveria ter. O problema do pinguim, e o que fazer no lugar.
A pergunta é sempre só o que o método precisa — esta instância, a classe, ou nenhum dos dois. Errar isso quebra subclasses em silêncio.
Python não precisa de getters e setters, porque @property deixa você acrescentar validação depois sem mudar uma única chamada.
Uma classe sem __repr__ desperdiça o seu tempo desde o instante em que existe. repr é para você, str é para quem lê, e um dos dois tem um fallback sensato.
self é um nome de parâmetro, não uma palavra-chave. __init__ não cria o objeto. E um atributo de classe é compartilhado até o momento em que você atribui pela instância.
A maioria das classes em Python deveria ser função. O teste não é “isso é um substantivo” — é se existe um estado inválido que a classe consegue impedir.
O que o f compila, a linguagem completa de especificação de formato, __format__, e os três trabalhos para os quais uma f-string é a ferramenta errada.
Contar, agrupar e manter uma fila são três laços que quase todo mundo escreve na mão. O módulo collections já tem os três.
O que o with realmente garante, o que __enter__ e __exit__ fazem, o atalho do contextlib e por que retornar True engole a exceção.
O decorator escreve __init__, __repr__ e __eq__ por você. Com default_factory, frozen, ordenação, __post_init__, asdict e replace.