
Passo 1 de 8
Definir o que torna um objeto válido
Reconheça as invariantes da classe Turma e use essas condições para distinguir estados válidos de inválidos.
Trilha de aprendizado · Nível 7 · Tutorial 3
Modelar objetos que mantêm suas regras de validade desde a inicialização até as mudanças de estado, oferecendo operações com responsabilidades claras.
Definir o que torna um objeto válido
Reconheça as invariantes da classe Turma e use essas condições para distinguir estados válidos de inválidos. 2 min
Oferecer operações, não alterações arbitrárias
Defina uma interface pública baseada em ações do domínio e diferencie-a dos detalhes internos da classe. 2 min
Estabelecer um estado inicial válido
Valide todos os dados e suas relações antes de armazenar o estado inicial de uma Turma. 2 min
Validar cada mudança de estado
Implemente operações públicas que validam o argumento e o estado atual antes de modificar a instância. 3 min
Rejeitar sem deixar alterações pela metade
Prepare e valide o estado completo proposto antes de substituir os atributos da instância. 3 min
Concentrar regras em um método interno
Reutilize as invariantes na inicialização e nas mudanças de estado, mantendo separadas a validação e a alteração dos atributos. 2 min
Impedir que coleções contornem as regras
Controle as referências recebidas e devolvidas pela classe para impedir mudanças externas no estado interno. 3 min
Aplicar e revisar a preservação das regras
Implemente uma operação de substituição e confirme que mudanças válidas são aplicadas, mudanças inválidas preservam o estado anterior e listas externas não alteram a coleção interna. 4 min

Passo 1 de 8
Reconheça as invariantes da classe Turma e use essas condições para distinguir estados válidos de inválidos.
Uma invariante é uma condição que caracteriza todo estado válido de um objeto. Ela deve ser verdadeira logo após a inicialização e continuar verdadeira depois de cada operação pública bem-sucedida.
Considere uma classe Turma com dois dados: uma capacidade e uma lista de identificadores de inscritos. A própria classe deve manter suas invariantes, em vez de depender apenas do cuidado de quem a utiliza.
O estado da turma combina uma capacidade com a coleção de identificadores inscritos.

A validade depende tanto de cada dado quanto da relação entre eles.
Neste exemplo, um estado é válido somente quando todas estas condições são verdadeiras:
bool não é aceito;str não vazia;As três primeiras condições verificam atributos ou elementos isoladamente. A última relaciona duas partes do estado: a lista pode conter identificadores perfeitamente válidos e, ainda assim, ser grande demais para a capacidade.
Exemplo
Válido: capacidade 3; inscritos ["A17", "B04"].
Inválido por um valor isolado: capacidade True; inscritos []. Embora bool tenha relação com int em Python, a regra da turma o rejeita.
Inválido por duplicação: capacidade 3; inscritos ["A17", "A17"].
Inválido pela relação entre atributos: capacidade 1; inscritos ["A17", "B04"]. Cada atributo parece aceitável quando observado sozinho, mas há dois inscritos para uma única vaga.
Uma turma tem capacidade 2 e inscritos ["A17", "B04", "C91"]. Qual invariante é violada?

Passo 2 de 8
Defina uma interface pública baseada em ações do domínio e diferencie-a dos detalhes internos da classe.
As invariantes da Turma podem ser contornadas se qualquer código alterar livremente sua capacidade ou sua lista de inscritos. Em vez disso, a classe deve oferecer operações que expressem intenções do domínio: inscrever, cancelar_inscricao e alterar_capacidade.
Cada operação se torna um ponto controlado para decidir se a mudança é permitida. O código consumidor pede uma ação; a própria Turma fica responsável por preservar seu estado válido.
As operações públicas funcionam como entradas controladas para consultar ou modificar o objeto. O estado interno não deve ser o caminho normal de uso da classe.

A interface pública recebe as solicitações; os detalhes internos permanecem sob controle da classe.
A interface pública é o conjunto de operações e consultas que outros trechos do programa devem utilizar. Métodos como inscrever() expressam mudanças; consultas como consultar_capacidade() e quantidade_inscritos() permitem observar o estado.
Atributos como _capacidade e _inscritos representam detalhes internos. O prefixo _ comunica: “este nome é para uso interno da classe”.
Este trecho destaca as chamadas que o código consumidor deve fazer. A implementação das validações será construída nos próximos steps.
turma = Turma(30)
# Operações públicas: expressam intenções do domínio.
turma.inscrever("ana")
turma.cancelar_inscricao("ana")
turma.alterar_capacidade(35)
# Consultas públicas: observam o estado.
print(turma.consultar_capacidade())
print(turma.quantidade_inscritos())
# Evite manipular diretamente os detalhes internos:
# turma._capacidade = 0
# turma._inscritos.append("")Dica
Python permite acessar turma._capacidade deliberadamente. O prefixo _ não oferece segurança nem impede alterações: ele apenas sinaliza que o código consumidor não deve depender desse detalhe. A preservação das regras vem do uso disciplinado da interface pública e das validações implementadas pela classe.
Associe cada nome ao seu papel na classe Turma.
Toque em um item e depois no par correspondente.
A instrução turma._capacidade = 0 pode contornar as invariantes porque modifica um detalhe interno sem passar por uma operação pública de validação.

Passo 3 de 8
Valide todos os dados e suas relações antes de armazenar o estado inicial de uma Turma.
As invariantes da Turma já devem valer quando a inicialização termina: a capacidade precisa ser um inteiro positivo, sem aceitar bool; os inscritos devem formar uma lista de identificadores textuais não vazios e sem duplicatas; e a quantidade não pode superar a capacidade.
Por isso, __init__ deve primeiro validar a capacidade, os identificadores e a relação entre eles. Somente depois ele atribui _capacidade e _inscritos.
A inicialização funciona como uma fronteira: os dados recebidos atravessam todas as verificações antes de formar o estado da instância.

Nenhuma parte do estado é estabelecida antes de todas as invariantes serem confirmadas.
A lista candidata é própria da instância. As exceções distinguem tipos inadequados de valores que violam as regras.
class Turma:
def __init__(self, capacidade, inscritos):
if isinstance(capacidade, bool) or not isinstance(capacidade, int):
raise TypeError("capacidade deve ser um número inteiro, sem aceitar bool")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
if not isinstance(inscritos, list):
raise TypeError("inscritos deve ser uma lista")
inscritos_candidatos = list(inscritos)
for identificador in inscritos_candidatos:
if not isinstance(identificador, str):
raise TypeError("cada identificador deve ser um texto")
if identificador == "":
raise ValueError("identificadores não podem ser vazios")
if len(set(inscritos_candidatos)) != len(inscritos_candidatos):
raise ValueError("identificadores não podem estar duplicados")
if len(inscritos_candidatos) > capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")
self._capacidade = capacidade
self._inscritos = inscritos_candidatosExemplo
Neste caso, há dois inscritos para apenas uma vaga:
try:
turma = Turma(1, ["ana", "bia"])
except ValueError as erro:
print(erro)Resultado:
quantidade de inscritos excede a capacidadeComo __init__ sinalizou a falha, a chamada não terminou normalmente e não entregou uma nova Turma pronta para uso ao código chamador.
Dica
Use variáveis locais durante a validação. As atribuições a self ficam no final, depois de todas as verificações.
Qual sequência representa corretamente a responsabilidade de __init__ na classe Turma?

Passo 4 de 8
Implemente operações públicas que validam o argumento e o estado atual antes de modificar a instância.
Um identificador como "bia" pode ser válido isoladamente, mas a inscrição ainda deve ser rejeitada se ele já estiver na turma ou se não houver vaga. Da mesma forma, a capacidade 2 é positiva, porém não pode substituir uma capacidade maior quando já existem três inscritos.
Cada operação pública precisa verificar duas coisas: o argumento recebido e as condições atuais da instância. Somente depois de todas as verificações ela pode alterar o estado.
A proposta passa por verificações antes de alcançar o estado armazenado. Se alguma regra falhar, o caminho termina sem modificação.

A alteração acontece apenas no caminho aceito; uma rejeição preserva o estado anterior.
Nas operações simples abaixo, cada raise ocorre antes da instrução que modifica o atributo. Assim, uma inscrição duplicada, um cancelamento inexistente ou uma redução incompatível não produz nenhuma mudança.
Estes métodos consideram os argumentos e o estado atual da turma.
class Turma:
# __init__ validado no step anterior
def inscrever(self, identificador):
if not isinstance(identificador, str):
raise TypeError("identificador deve ser uma string")
if not identificador.strip():
raise ValueError("identificador não pode estar vazio")
if identificador in self._inscritos:
raise ValueError("identificador já está inscrito")
if len(self._inscritos) >= self._capacidade:
raise ValueError("não há vaga disponível")
self._inscritos.append(identificador)
def cancelar(self, identificador):
if not isinstance(identificador, str):
raise TypeError("identificador deve ser uma string")
if not identificador.strip():
raise ValueError("identificador não pode estar vazio")
if identificador not in self._inscritos:
raise ValueError("identificador não está inscrito")
self._inscritos.remove(identificador)
def alterar_capacidade(self, nova_capacidade):
if isinstance(nova_capacidade, bool) or not isinstance(
nova_capacidade, int
):
raise TypeError("nova capacidade deve ser um inteiro")
if nova_capacidade <= 0:
raise ValueError("nova capacidade deve ser positiva")
if nova_capacidade < len(self._inscritos):
raise ValueError(
"nova capacidade não comporta os inscritos atuais"
)
self._capacidade = nova_capacidadeDica
Em cada método, procure a linha que realmente altera _inscritos ou _capacidade. Todas as condições capazes de rejeitar a operação devem aparecer antes dela.
Exemplo
Considere uma turma iniciada com capacidade 2 e inscritos ["ana"]:
inscrever("bia") é aceita: há vaga e não existe duplicação. Estado: capacidade 2, inscritos ["ana", "bia"].inscrever("ana") é rejeitada: o identificador já existe. O estado não muda.alterar_capacidade(1) é rejeitada: duas inscrições não cabem na nova capacidade. O estado não muda.cancelar("ana") é aceita. Estado: capacidade 2, inscritos ["bia"].alterar_capacidade(1) agora é aceita, pois a única inscrição existente cabe no novo limite.Nas chamadas 3 e 5, o argumento é o mesmo: 1. O resultado muda porque a validade da operação depende da ocupação no momento da chamada.
Complete a condição:
if nova_capacidade < ____:
raise ValueError("nova capacidade não comporta os inscritos atuais")
Uma turma começa com capacidade 2 e inscritos ["ana"]. As exceções são capturadas para que a sequência continue:
inscrever("bia")inscrever("ana")alterar_capacidade(1)cancelar("caio")Qual é o estado final?

Passo 5 de 8
Prepare e valide o estado completo proposto antes de substituir os atributos da instância.
Considere uma operação reconfigurar que recebe, ao mesmo tempo, uma nova capacidade e uma nova lista de inscritos. As duas partes precisam formar juntas um estado válido.
A operação deve primeiro preparar um estado candidato em variáveis locais. Somente depois de validar todas as regras ela pode substituir _capacidade e _inscritos.
Se qualquer regra falhar, uma exceção interrompe o fluxo enquanto o estado anterior da instância permanece intacto.
A validação funciona como uma barreira entre a proposta e o estado armazenado.

Uma proposta aceita substitui o conjunto completo; uma proposta rejeitada não altera nenhuma parte do objeto.
No código abaixo, a capacidade é alterada antes de a lista proposta ser completamente validada. Se uma verificação posterior executar raise, Python interromperá o método, mas não desfará a atribuição já realizada.
Esta versão pode deixar a instância parcialmente atualizada.
def reconfigurar(self, capacidade, inscritos):
if isinstance(capacidade, bool) or not isinstance(capacidade, int):
raise TypeError("capacidade deve ser um inteiro")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
self._capacidade = capacidade # alteração antecipada
if not isinstance(inscritos, list):
raise TypeError("inscritos deve ser uma lista")
if any(not isinstance(item, str) for item in inscritos):
raise TypeError("cada identificador deve ser uma string")
if any(item == "" for item in inscritos):
raise ValueError("identificadores não podem ser vazios")
if len(set(inscritos)) != len(inscritos):
raise ValueError("identificadores não podem se repetir")
if len(inscritos) > capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")
self._inscritos = list(inscritos)Atenção
Se a turma tinha capacidade 3 e três inscritos, uma tentativa de mudar para capacidade 2 com uma lista inválida pode alterar _capacidade para 2 e depois falhar. A instância fica com três inscritos para apenas duas vagas, violando suas próprias regras.
As variáveis locais recebem a proposta completa. Nenhum atributo é alterado durante a validação.
def reconfigurar(self, capacidade, inscritos):
if isinstance(capacidade, bool) or not isinstance(capacidade, int):
raise TypeError("capacidade deve ser um inteiro")
if not isinstance(inscritos, list):
raise TypeError("inscritos deve ser uma lista")
nova_capacidade = capacidade
novos_inscritos = list(inscritos)
if nova_capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
if any(not isinstance(item, str) for item in novos_inscritos):
raise TypeError("cada identificador deve ser uma string")
if any(item == "" for item in novos_inscritos):
raise ValueError("identificadores não podem ser vazios")
if len(set(novos_inscritos)) != len(novos_inscritos):
raise ValueError("identificadores não podem se repetir")
if len(novos_inscritos) > nova_capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")
self._capacidade = nova_capacidade
self._inscritos = novos_inscritosExemplo
Se o estado atual for capacidade 3 e inscritos ["ana", "bia", "caio"], a proposta 2, ["ana", "ana"] será rejeitada pela duplicação. Como as atribuições aos atributos estão no final, o objeto continuará com capacidade 3 e os mesmos três inscritos.
Já a proposta 2, ["ana", "bia"] passa por todas as verificações e substitui o estado completo.
Dica
Use a sequência: construir o estado candidato, validar todas as suas partes e relações e, por último, efetivar as atribuições. As variáveis locais podem ser descartadas em caso de erro sem comprometer o objeto.
Coloque as etapas de uma reconfiguração na ordem que preserva o estado anterior quando ocorre uma rejeição.
Uma turma começa com capacidade 3 e inscritos ["ana", "bia", "caio"]. A implementação problemática atribui primeiro self._capacidade = 2 e depois rejeita a proposta por conter identificadores duplicados. Como a instância fica?

Passo 6 de 8
Reutilize as invariantes na inicialização e nas mudanças de estado, mantendo separadas a validação e a alteração dos atributos.
Quando várias operações precisam preservar as mesmas invariantes, repetir as verificações em cada método aumenta o risco de inconsistência. Um método interno pode receber explicitamente a capacidade e os inscritos candidatos, sinalizar qualquer falha e terminar sem modificar a instância. Somente depois dessa validação a operação efetiva as atribuições.
A inicialização e as operações públicas enviam suas propostas ao mesmo validador. Uma proposta válida pode substituir o estado; uma proposta inválida é rejeitada, preservando o estado anterior.

O validador examina valores candidatos, não apenas os atributos que já estão armazenados.
O método _validar_estado apenas verifica os valores recebidos e levanta exceções. Ele não atribui valores a _capacidade nem a _inscritos.
class Turma:
def __init__(self, capacidade, inscritos):
self._validar_estado(capacidade, inscritos)
self._capacidade = capacidade
self._inscritos = list(inscritos)
def _validar_estado(self, capacidade, inscritos):
if isinstance(capacidade, bool) or not isinstance(capacidade, int):
raise TypeError("capacidade deve ser um inteiro")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
if not isinstance(inscritos, list):
raise TypeError("inscritos deve ser uma lista")
for identificador in inscritos:
if not isinstance(identificador, str):
raise TypeError("cada identificador deve ser textual")
if not identificador.strip():
raise ValueError("identificadores não podem ser vazios")
if len(set(inscritos)) != len(inscritos):
raise ValueError("não pode haver inscrições duplicadas")
if len(inscritos) > capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")
def inscrever(self, identificador):
candidatos = self._inscritos + [identificador]
self._validar_estado(self._capacidade, candidatos)
self._inscritos = candidatos
def cancelar_inscricao(self, identificador):
if identificador not in self._inscritos:
raise ValueError("a inscrição informada não existe")
candidatos = list(self._inscritos)
candidatos.remove(identificador)
self._validar_estado(self._capacidade, candidatos)
self._inscritos = candidatos
def alterar_capacidade(self, nova_capacidade):
self._validar_estado(nova_capacidade, self._inscritos)
self._capacidade = nova_capacidadeExemplo
“A capacidade deve ser positiva” e “não pode haver duplicatas” são invariantes do estado completo, por isso pertencem a _validar_estado. Já “a inscrição precisa existir antes do cancelamento” é uma condição específica de cancelar_inscricao: sem ela, remover o item produziria uma falha da implementação ou transformaria o cancelamento em uma operação silenciosa.
Dica
Se o validador consultasse apenas self._capacidade e self._inscritos, ele não conseguiria rejeitar uma proposta antes da alteração. Receber os candidatos também permite reutilizá-lo durante __init__, quando os atributos ainda não foram estabelecidos.
Quais regras da classe Turma devem ficar no validador interno, qual condição deve permanecer especificamente em cancelar_inscricao e por que o validador deve receber valores candidatos sem alterar a instância?
Escreva pelo menos 100 caracteres (0/100).

Passo 7 de 8
Controle as referências recebidas e devolvidas pela classe para impedir mudanças externas no estado interno.
Validar as operações públicas não basta se uma lista externa apontar para a mesma coleção usada pela instância. Isso acontece quando a classe guarda diretamente a lista recebida ou devolve sua própria lista interna.
Nesse caso, outro código pode usar append, remove ou uma atribuição por índice para introduzir duplicatas ou exceder a capacidade — tudo sem chamar inscrever, cancelar_inscricao ou outra operação validada. Esse compartilhamento indevido é um vazamento de referência.
Compare os dois caminhos entre o código externo e a coleção interna.

À esquerda, a mesma lista atravessa a interface e pode ser alterada por fora. À direita, cópias independentes interrompem esse caminho.
Os dois retornos marcados entregam acesso à mesma lista mantida pela instância.
class Turma:
def __init__(self, capacidade, inscritos):
self._validar_estado(capacidade, inscritos)
self._capacidade = capacidade
self._inscritos = inscritos # guarda a lista recebida
def consultar_inscritos(self):
return self._inscritos # devolve a lista interna
def _validar_estado(self, capacidade, inscritos):
if type(capacidade) is not int:
raise TypeError("capacidade deve ser um inteiro")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
if any(type(item) is not str or not item.strip() for item in inscritos):
raise ValueError("cada identificador deve ser um texto não vazio")
if len(set(inscritos)) != len(inscritos):
raise ValueError("não pode haver identificadores duplicados")
if len(inscritos) > capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")
lista_externa = ["ana"]
turma = Turma(1, lista_externa)
lista_externa.append("bia")
turma.consultar_inscritos().append("ana")
print(turma.consultar_inscritos())
# ['ana', 'bia', 'ana']Exemplo
O estado foi válido durante a inicialização, mas a instância continuou compartilhando sua lista com o código externo. As duas chamadas a append ignoraram a validação: a capacidade foi excedida e surgiu uma duplicata. O prefixo _ comunica que _inscritos é interno, mas não corrige o compartilhamento da referência.
Crie uma lista própria antes de validar e armazenar. Na consulta, devolva um retrato que não permita alterar a lista interna.
class Turma:
def __init__(self, capacidade, inscritos):
inscritos_candidatos = list(inscritos)
self._validar_estado(capacidade, inscritos_candidatos)
self._capacidade = capacidade
self._inscritos = inscritos_candidatos
def consultar_inscritos(self):
return tuple(self._inscritos)
def _validar_estado(self, capacidade, inscritos):
if type(capacidade) is not int:
raise TypeError("capacidade deve ser um inteiro")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
if any(type(item) is not str or not item.strip() for item in inscritos):
raise ValueError("cada identificador deve ser um texto não vazio")
if len(set(inscritos)) != len(inscritos):
raise ValueError("não pode haver identificadores duplicados")
if len(inscritos) > capacidade:
raise ValueError("quantidade de inscritos excede a capacidade")list(inscritos) cria a coleção que ficará sob responsabilidade da instância. Alterar a lista original depois da inicialização não modifica _inscritos.
Na saída, tuple(self._inscritos) produz um retrato das inscrições naquele momento. Quem recebe a tupla pode consultá-la, mas não usar operações de lista para modificar a coleção interna. Outra opção segura seria devolver list(self._inscritos), isto é, uma nova lista que o código externo poderia alterar sem afetar a instância.
Dica
Essas são cópias rasas. Uma tupla impede a substituição, inclusão ou remoção de seus itens, mas não torna imutáveis objetos mutáveis armazenados dentro dela. Neste exemplo, isso é suficiente porque os identificadores são strings, e strings são imutáveis.
Considere uma Turma que copia a lista recebida, oferece inscrever com validação e retorna tuple(self._inscritos) na consulta. Após o código abaixo, retrato continua sendo ('ana',), enquanto uma nova consulta retorna ('ana', 'bia').
original = ["ana"]
turma = Turma(2, original)
retrato = turma.consultar_inscritos()
original.append("caio")
turma.inscrever("bia")Retornar uma tupla garante que qualquer elemento mutável armazenado dentro dela também fique completamente protegido contra alterações externas.

Passo 8 de 8
Implemente uma operação de substituição e confirme que mudanças válidas são aplicadas, mudanças inválidas preservam o estado anterior e listas externas não alteram a coleção interna.
Uma classe preserva suas invariantes quando:
Você aplicará esses compromissos à operação substituir_inscrito(atual, novo). Ela não cria uma regra nova: apenas troca um identificador existente por outro e reutiliza as invariantes da Turma.
A substituição deve ser preparada em uma cópia. Somente um estado candidato aprovado pode substituir o estado atual.

A validação acontece sobre o candidato; uma rejeição não alcança o estado armazenado.
Crie um arquivo chamado turma.py e copie o código completo abaixo. Depois, substitua apenas o corpo de substituir_inscrito.
Sua implementação deve:
atual não estiver inscrito;_inscritos;_validar_estado com a capacidade atual e a lista candidata;_inscritos apenas depois da validação.Não altere _inscritos antes de todas essas verificações.
Complete o método indicado e execute o script localmente.
class Turma:
def __init__(self, capacidade, inscritos):
if not isinstance(inscritos, list):
raise TypeError("inscritos deve ser uma lista")
candidatos = list(inscritos)
self._validar_estado(capacidade, candidatos)
self._capacidade = capacidade
self._inscritos = candidatos
def _validar_estado(self, capacidade, inscritos):
if isinstance(capacidade, bool) or not isinstance(capacidade, int):
raise TypeError("capacidade deve ser um inteiro, sem aceitar bool")
if capacidade <= 0:
raise ValueError("capacidade deve ser positiva")
for identificador in inscritos:
if not isinstance(identificador, str):
raise TypeError("cada identificador deve ser textual")
if not identificador.strip():
raise ValueError("identificadores não podem ser vazios")
if len(set(inscritos)) != len(inscritos):
raise ValueError("não pode haver identificadores duplicados")
if len(inscritos) > capacidade:
raise ValueError("a quantidade de inscritos excede a capacidade")
def consultar_capacidade(self):
return self._capacidade
def consultar_inscritos(self):
return list(self._inscritos)
def inscrever(self, identificador):
candidatos = self._inscritos + [identificador]
self._validar_estado(self._capacidade, candidatos)
self._inscritos = candidatos
def cancelar_inscricao(self, identificador):
if identificador not in self._inscritos:
raise ValueError("a inscrição informada não existe")
candidatos = list(self._inscritos)
candidatos.remove(identificador)
self._validar_estado(self._capacidade, candidatos)
self._inscritos = candidatos
def alterar_capacidade(self, nova_capacidade):
self._validar_estado(nova_capacidade, self._inscritos)
self._capacidade = nova_capacidade
def reconfigurar(self, nova_capacidade, novos_inscritos):
if not isinstance(novos_inscritos, list):
raise TypeError("novos_inscritos deve ser uma lista")
candidatos = list(novos_inscritos)
self._validar_estado(nova_capacidade, candidatos)
self._capacidade = nova_capacidade
self._inscritos = candidatos
def substituir_inscrito(self, atual, novo):
# Implemente aqui.
raise NotImplementedError
lista_inicial = ["ana", "bia"]
turma = Turma(3, lista_inicial)
print("Inicial:", turma.consultar_inscritos())
# Nem a lista de entrada nem o resultado da consulta devem alterar a turma.
lista_inicial.append("externo-1")
retrato = turma.consultar_inscritos()
retrato.append("externo-2")
print("Após listas externas:", turma.consultar_inscritos())
# Mudança válida.
turma.substituir_inscrito("ana", "caio")
print("Substituição válida:", turma.consultar_inscritos())
# A duplicação deve ser rejeitada sem remover "caio".
antes = turma.consultar_inscritos()
try:
turma.substituir_inscrito("caio", "bia")
except ValueError as erro:
print("Rejeitada:", erro)
print("Estado preservado:", turma.consultar_inscritos())
print("Igual ao estado anterior:", turma.consultar_inscritos() == antes)Exemplo
Ao executar sua implementação, a saída deve seguir este formato:
Inicial: ['ana', 'bia']
Após listas externas: ['ana', 'bia']
Substituição válida: ['caio', 'bia']
Rejeitada: não pode haver identificadores duplicados
Estado preservado: ['caio', 'bia']
Igual ao estado anterior: True
A mensagem da rejeição vem de _validar_estado. O ponto decisivo é o estado final: a tentativa de substituir caio por bia não pode remover caio nem criar uma duplicata.
Explique o que aconteceu na substituição válida, na tentativa que produziria uma duplicata e nas alterações feitas às duas listas externas.
Escreva pelo menos 80 caracteres (0/80).
Compare sua tentativa com a solução abaixo. Observe especialmente que self._inscritos aparece no lado esquerdo de uma atribuição somente depois que o candidato foi aprovado.
Este é o corpo completo que substitui o método incompleto da classe-base.
def substituir_inscrito(self, atual, novo):
if atual not in self._inscritos:
raise ValueError("a inscrição informada não existe")
candidatos = list(self._inscritos)
indice = candidatos.index(atual)
candidatos[indice] = novo
self._validar_estado(self._capacidade, candidatos)
self._inscritos = candidatosResumo
Parabéns! Você concluiu: Preservar regras de validade em objetos
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