
Passo 1 de 6
O que pertence à classe e o que pertence ao objeto
Identifique se um dado representa uma característica comum ao tipo ou o estado individual de cada objeto.
Trilha de aprendizado · Nível 7 · Tutorial 2
Escolher onde armazenar cada atributo e corrigir compartilhamentos acidentais de estado entre objetos.
O que pertence à classe e o que pertence ao objeto
Identifique se um dado representa uma característica comum ao tipo ou o estado individual de cada objeto. 2 min
De onde vem o valor consultado
Acompanhe o caminho de consulta de um atributo e preveja se o valor será encontrado na instância ou na classe. 2 min
Atribuir na instância pode ocultar o valor da classe
Veja como uma atribuição individual cria um atributo próprio e como isso afeta consultas após a alteração do valor comum da classe. 3 min
Reatribuir não é modificar uma coleção
Compare mutação e reatribuição para diagnosticar listas e dicionários compartilhados acidentalmente entre instâncias. 3 min
Criar uma coleção própria para cada instância
Mova listas e dicionários individuais para __init__ e garanta que cada objeto receba coleções independentes. 3 min
Aplicação final: corrigir e explicar o estado dos objetos
Analise um compartilhamento acidental de estado, corrija a classe e confirme como consultas, mutações e atribuições afetam duas instâncias. 3 min

Passo 1 de 6
Identifique se um dado representa uma característica comum ao tipo ou o estado individual de cada objeto.
Um atributo definido diretamente no corpo da classe pertence à classe. Ele é adequado quando o valor representa uma característica intencionalmente comum ao tipo.
Já os atributos definidos com self pertencem a cada instância. Eles representam o estado individual de cada objeto.
Nesta modelagem, todos os cadernos têm o formato A4, mas cada objeto mantém seu próprio título.
class Caderno:
formato = "A4"
def __init__(self, titulo):
self.titulo = titulo
estudos = Caderno("Estudos")
receitas = Caderno("Receitas")Em Caderno, formato foi declarado na classe porque representa uma característica comum a todos os cadernos desse tipo. titulo foi associado a self porque descreve cada caderno individualmente.
A decisão deve seguir o significado do dado, não apenas os valores encontrados agora.
O elemento superior representa a classe e sua característica comum. Os dois elementos inferiores representam instâncias distintas, cada uma com seu próprio título.

O formato é comum ao tipo; o título faz parte do estado de cada caderno.
Dica
Se dois cadernos tiverem o título "Anotações", isso não torna o título uma característica da classe. Os valores podem coincidir, mas cada título continua representando o estado de um objeto específico.
Relacione cada declaração ou situação à classificação correta.
Toque em um item e depois no par correspondente.

Passo 2 de 6
Acompanhe o caminho de consulta de um atributo e preveja se o valor será encontrado na instância ou na classe.
Ao consultar objeto.atributo, Python procura primeiro esse nome na própria instância. Se não o encontrar, procura na classe.
No exemplo, cada caderno possui seu próprio titulo. Já formato está na classe e pode ser consultado por qualquer instância.
Observe onde cada valor está armazenado.
class Caderno:
formato = "A5"
def __init__(self, titulo):
self.titulo = titulo
azul = Caderno("Estudos")
verde = Caderno("Receitas")
print(azul.titulo) # Estudos: encontrado na instância azul
print(verde.titulo) # Receitas: encontrado na instância verde
print(azul.formato) # A5: encontrado na classe Caderno
print(verde.formato) # A5: encontrado na classe Caderno
A instância é consultada primeiro. Somente quando o nome não está nela, a busca segue para a classe.
Ao usar Caderno.formato, a consulta começa na própria classe e encontra "A5".
Já Caderno.titulo não procura o título de azul, de verde nem de qualquer outra instância. Como titulo não foi definido na classe, essa consulta causa AttributeError.
print(Caderno.formato) # A5
# Caderno.titulo causaria AttributeError,
# pois titulo pertence a cada instância.Dica
Quando azul.formato encontra formato na classe, Python apenas usa o valor disponível ali. Esse acesso não cria automaticamente uma cópia de formato dentro de azul.
Considerando o código anterior, o que será exibido por print(verde.titulo, verde.formato)?
Associe cada expressão ao resultado e à origem do atributo.
Toque em um item e depois no par correspondente.

Passo 3 de 6
Veja como uma atribuição individual cria um atributo próprio e como isso afeta consultas após a alteração do valor comum da classe.
Nas classes simples deste tutorial, atribuir por objeto.atributo cria ou atualiza esse atributo somente naquela instância. Se a classe já tiver um atributo com o mesmo nome, o valor individual passa a ocultá-lo nas consultas feitas por esse objeto.
A mesma regra vale para uma atribuição como self.atributo = valor dentro de um método: self indica a instância que recebe o atributo.
A atribuição em caderno_1 não modifica a classe nem acrescenta o atributo a caderno_2.
class Caderno:
formato = "A5"
def __init__(self, titulo):
self.titulo = titulo
caderno_1 = Caderno("Estudos")
caderno_2 = Caderno("Receitas")
caderno_1.formato = "A4"
print(Caderno.formato) # A5
print(caderno_1.formato) # A4
print(caderno_2.formato) # A5Agora considere uma atribuição posterior: Caderno.formato = "Carta". Ela altera o atributo da classe.
caderno_1 continua mostrando "A4", pois já possui um atributo individual chamado formato. Já caderno_2, que não possui esse atributo próprio, passa a encontrar "Carta" na classe — mesmo tendo sido criado antes da alteração.
O diagrama acompanha o estado final: a classe guarda "Carta"; o primeiro objeto guarda seu próprio "A4"; o segundo não guarda um formato individual e continua consultando a classe.

Um atributo próprio oculta o de classe apenas para a instância que o recebeu.
Considere a sequência completa: primeiro caderno_1.formato = "A4"; depois Caderno.formato = "Carta". Complete o resultado de cada consulta.
Depois das duas atribuições, Caderno.formato vale _.
Depois das duas atribuições, caderno_1.formato vale _.
Depois das duas atribuições, caderno_2.formato vale _.

Passo 4 de 6
Compare mutação e reatribuição para diagnosticar listas e dicionários compartilhados acidentalmente entre instâncias.
Quando uma lista ou um dicionário é definido no corpo da classe, várias instâncias podem encontrar o mesmo objeto mutável. Se uma delas modificar essa coleção, a mudança também será observada pela outra.
Isso é acidental quando os dados deveriam representar o estado individual de cada objeto.
As duas instâncias encontram as mesmas coleções definidas em Caderno.
class Caderno:
notas = []
marcadores = {}
caderno_a = Caderno()
caderno_b = Caderno()
caderno_a.notas.append(8.5)
caderno_a.marcadores["revisar"] = True
print(caderno_a.notas) # [8.5]
print(caderno_b.notas) # [8.5]
print(caderno_a.marcadores) # {'revisar': True}
print(caderno_b.marcadores) # {'revisar': True}Nos dois casos, os caminhos iniciados pelas instâncias chegam às coleções armazenadas na classe.

À esquerda, mutar a coleção afeta o objeto compartilhado. À direita, reatribuir o atributo separa apenas uma das instâncias.
caderno_a.notas.append(8.5) modifica a lista já encontrada. Isso não cria automaticamente um atributo notas em caderno_a.
Da mesma forma, caderno_a.marcadores["cor"] = "azul" modifica o dicionário encontrado. A atribuição acontece em uma chave do dicionário, não no atributo da instância.
Já caderno_a.notas = [...] e caderno_a.marcadores = {...} reatribuem os atributos em caderno_a. As novas coleções ocultam as coleções de mesmo nome existentes na classe.
Compare o que cada objeto consulta depois das operações.
class Caderno:
notas = []
marcadores = {}
caderno_a = Caderno()
caderno_b = Caderno()
# Mutação: altera as coleções compartilhadas.
caderno_a.notas.append(7.0)
caderno_a.marcadores["revisar"] = True
# Reatribuição: cria associações próprias em caderno_a.
caderno_a.notas = [10.0]
caderno_a.marcadores = {"favorito": True}
print(caderno_a.notas) # [10.0]
print(caderno_b.notas) # [7.0]
print(caderno_a.marcadores) # {'favorito': True}
print(caderno_b.marcadores) # {'revisar': True}Atenção
Em objeto.atributo = nova_colecao, o atributo da instância é reatribuído. Em objeto.dicionario[chave] = valor, quem é modificado é o dicionário encontrado pela consulta do atributo. Essas operações não têm o mesmo efeito.
Associe cada operação ao seu efeito, considerando que notas e marcadores foram definidos na classe.
Toque em um item e depois no par correspondente.
Analise o código. Quais são as quatro saídas? Explique por que as mudanças realizadas por caderno_a aparecem em caderno_b.
class Caderno:
notas = []
marcadores = {}
caderno_a = Caderno()
caderno_b = Caderno()
caderno_a.notas.append("Python")
caderno_a.marcadores["página"] = 12
print(caderno_a.notas)
print(caderno_b.notas)
print(caderno_a.marcadores)
print(caderno_b.marcadores)Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 6
Mova listas e dicionários individuais para init e garanta que cada objeto receba coleções independentes.
Notas e marcadores representam o estado de um caderno específico. Por isso, devem ser atribuídos a self dentro de __init__.
Cada chamada de Caderno(...) executa __init__ novamente. Assim, os literais [] e {} criam novas coleções para aquela instância.
Somente formato, que é comum a todos os cadernos, permanece na classe.
class Caderno:
formato = "A5"
def __init__(self, titulo):
self.titulo = titulo
self.notas = []
self.marcadores = {}
Dica
Pergunte: “Uma alteração neste dado deve aparecer nos outros objetos?” Se a resposta for não, inicialize o dado em self.
Ao criar dois cadernos, cada execução de __init__ produz uma lista e um dicionário novos. Alterar as coleções de estudos não modifica as coleções de viagem.
Execute este trecho depois da definição corrigida da classe.
estudos = Caderno("Estudos")
viagem = Caderno("Viagem")
estudos.notas.append("Revisar classes")
estudos.marcadores["Python"] = 12
print(estudos.notas) # ['Revisar classes']
print(viagem.notas) # []
print(estudos.marcadores) # {'Python': 12}
print(viagem.marcadores) # {}
print(estudos.formato) # A5
print(viagem.formato) # A5
O formato é compartilhado pela classe; notas e marcadores pertencem separadamente a cada instância.
Atenção
A linha self.notas = Caderno.notas cria um atributo na instância, mas seu valor ainda é uma referência à lista da classe. Nenhuma lista nova é criada.
Este código parece mover os dados para a instância, mas reutiliza as coleções existentes.
class Caderno:
formato = "A5"
notas = []
marcadores = {}
def __init__(self, titulo):
self.titulo = titulo
self.notas = Caderno.notas
self.marcadores = Caderno.marcadoresDica
Para obter independência, atribua novas coleções: self.notas = [] e self.marcadores = {}. Referenciar Caderno.notas ou Caderno.marcadores apenas reutiliza os objetos já compartilhados.
Complete a inicialização para que cada caderno tenha sua própria lista:
self.notas = ___
Complete a inicialização para que cada caderno tenha seus próprios marcadores:
self.marcadores = ___
A instrução self.notas = Caderno.notas cria uma lista independente para a instância.

Passo 6 de 6
Analise um compartilhamento acidental de estado, corrija a classe e confirme como consultas, mutações e atribuições afetam duas instâncias.
O script abaixo define duas coleções na classe, embora elas representem dados individuais de cada caderno. Primeiro, preveja as três linhas de saída. Depois, copie o código para um arquivo no seu computador e execute-o com Python 3 para conferir.
Salve, por exemplo, como cadernos.py e execute com Python 3.
class Caderno:
formato = "A5"
notas = []
marcadores = {}
def __init__(self, titulo):
self.titulo = titulo
estudos = Caderno("Estudos")
viagem = Caderno("Viagem")
estudos.notas.append("Revisar classes")
estudos.marcadores["POO"] = 12
estudos.formato = "A4"
Caderno.formato = "A6"
print(estudos.notas, viagem.notas)
print(estudos.marcadores, viagem.marcadores)
print(estudos.formato, viagem.formato, Caderno.formato)Quais são as três linhas de saída? Justifique por que as coleções aparecem nos dois objetos e por que a alteração de Caderno.formato afeta viagem, mas não muda o valor consultado por estudos.
Escreva pelo menos 100 caracteres (0/100).
Mantenha formato na classe, pois ele representa um valor comum ao tipo. Mova notas e marcadores para init: os literais [] e {} serão avaliados novamente a cada inicialização, criando coleções diferentes para cada instância. Execute esta versão no seu computador.
Este script é completo e pode substituir a versão anterior.
class Caderno:
formato = "A5"
def __init__(self, titulo):
self.titulo = titulo
self.notas = []
self.marcadores = {}
estudos = Caderno("Estudos")
viagem = Caderno("Viagem")
estudos.notas.append("Revisar classes")
estudos.marcadores["POO"] = 12
estudos.formato = "A4"
Caderno.formato = "A6"
print(estudos.notas, viagem.notas)
print(estudos.marcadores, viagem.marcadores)
print(estudos.formato, viagem.formato, Caderno.formato)O diagrama contrasta as coleções independentes com o formato compartilhado. A instância estudos também possui um formato próprio, que oculta o valor da classe somente para ela.

Após a correção, cada caderno referencia suas próprias coleções; somente o valor comum permanece na classe.
Depois de executar a versão corrigida, registre as três linhas exibidas. Explique por que as coleções de viagem permanecem vazias e por que estudos mostra A4 enquanto viagem e Caderno mostram A6.
Escreva pelo menos 120 caracteres (0/120).
Resumo
Escolha o local do atributo pelo significado do dado e depois preveja como ele será consultado ou alterado.
Parabéns! Você concluiu: Distinguir atributos de instância e de classe
100 XP
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks