O Que É Um Atributo De Classe
Atributo de classe é uma variável compartilhada entre todas as instâncias de uma classe
Quando você define um atributo diretamente no corpo da classe, em vez de dentro de um método __init__ ou qualquer outro método de instância, esse atributo pertence à própria classe. Todas as instâncias criadas a partir dela compartilham o mesmo valor. Isso é diferente de atributos de instância, que são isolados para cada objeto. Eu já vi gente confundir isso e acabar com bugs difíceis de rastrear. O problema é que o atributo de classe existe antes de qualquer instância ser criada. Ele é avaliado uma única vez, no momento da definição da classe. Se você usar um valor mutável como lista ou dicionário, todas as instâncias vão compartilhar a mesma referência, não cópias independentes.
Pra que serve na prática
Eu uso atributos de classe basicamente para duas coisas: manter um contador de instâncias criadas e armazenar configurações globais que todo mundo precisa acessar. Um exemplo simples seria uma classe que rastreia quantos objetos foram instanciados: Cada vez que uma nova instância é criada, o total sobe. Isso funciona porque total é um atributo da classe, não da instância. Depois de anos lidando com isso, a maior dor de cabeça que eu encontrei foi com mutáveis. Eu tinha uma classe onde o atributo de classe era um dicionário vazio, e eu esperava que cada instância tivesse seu próprio dicionário. Não tinha. Todas apontavam para o mesmo objeto na memória. O código parecia correto, mas os dados de uma instância vazavam para as outras.
A solução que eu parti pra cima foi inicializar o atributo dentro do __init__, atribuindo uma cópia nova a cada instância. Ponto. Não tente economizar criando um atributo de classe como dicionário compartilhado a menos que seja exatamente isso que você quer.

Um detalhe técnico que faz diferença
Quando você acessa um atributo em uma instância, o Python procura primeiro na instância, depois na classe. Se você fizer uma atribuição via instância usando NotacaoPonto, ele cria um atributo de instância com o mesmo nome, escondendo o atributo de classe. Isso é silencioso e acontece o tempo todo. Se você quer modificar o atributo de classe a partir de um método de instância, use NomeDaClasse.nomeAtributo em vez de self.nomeAtributo. Atributos de classe não são para dados que mudam por instância. Se cada objeto precisa ter seu próprio estado, use atributos de instância no __init__. Atributos de classe são para constantes, contadores, configurações compartilhadas ou qualquer coisa que realmente deva ser única e coletiva. O grande risco é achar que está usando um atributo de instância quando na verdade está mexendo no da classe, ou vice-versa. O Python não grita quando isso acontece. Ele apenas faz algo que talvez não seja o esperado. E aí você perde horas debugando.
Galeria
-
O que é Classe, Método, Atributo e Objeto? -
Diagrama De Classe Uml Exemplos - RETOEDU -
Diagrama de Classes.pdf -
Diagrama de Classes Objetivos Prover respostas para as