Exercícios de Python intermediário com respostas

As 97 questões saem dos testes rápidos das aulas do Curso de Python Intermediário, na ordem do curso, e vão de compreensões de lista a testes automatizados. Tente responder sem consultar nada antes de abrir o gabarito: cada explicação mostra o porquê da resposta e indica a aula que ensina o tema.

Como usar: leia a pergunta, escolha a sua alternativa e só depois abra "Ver a resposta". Quando errar, a explicação diz por que e o link leva à aula que ensina o assunto. As mesmas questões aparecem nas aulas como teste rápido, e o Curso de Python Intermediário é gratuito do começo ao fim.

Módulo 1: Boas-vindas ao Python Intermediário

Questão 1 · aula Do básico para o intermediário: o que muda

O que melhor descreve o salto do Python básico para o intermediário?

  1. Aprender uma linguagem totalmente diferente do zero.
  2. Decorar dezenas de comandos novos sem usar o que já sabe.
  3. Usar a mesma base com mais organização, escrevendo código legível e reaproveitável.
  4. Abandonar variáveis, laços e funções e usar só classes.
Ver a resposta

Resposta: C. Usar a mesma base com mais organização, escrevendo código legível e reaproveitável.

O intermediário reaproveita tudo do Básico (variáveis, laços, funções) e acrescenta organização: código legível, reaproveitável e confiável. Há recursos novos, como orientação a objetos, mas o fio condutor é escrever melhor, não recomeçar.

Estudar a aula: Do básico para o intermediário: o que muda

Questão 2 · aula Revisão relâmpago do básico

Por que a função calcular_media usa return em vez de print?

  1. Porque print não funciona dentro de funções.
  2. Para devolver o valor e poder usá-lo depois, por exemplo passando para situacao().
  3. Porque return é mais rápido que print.
  4. Não faz diferença, os dois fazem a mesma coisa.
Ver a resposta

Resposta: B. Para devolver o valor e poder usá-lo depois, por exemplo passando para situacao().

return devolve o resultado para quem chamou, então dá para guardar em uma variável e passar para outra função (situacao(m)). Uma função que só imprime não permite reaproveitar o valor. Essa distinção é a base de todo o intermediário.

Estudar a aula: Revisão relâmpago do básico

Questão 3 · aula Seu ambiente e o Playground do curso

Por que o programa importou statistics em vez de calcular a mediana na mão?

  1. Porque o Python não deixa calcular mediana sem importar.
  2. Para reaproveitar um módulo pronto e testado, deixando o código curto e claro.
  3. Porque import é obrigatório em todo programa intermediário.
  4. Para o programa rodar mais rápido, e por nenhum outro motivo.
Ver a resposta

Resposta: B. Para reaproveitar um módulo pronto e testado, deixando o código curto e claro.

A biblioteca padrão traz módulos prontos e testados, como statistics. Importar em vez de reescrever deixa o código mais curto, claro e confiável. É o espírito do intermediário: aproveitar o que já existe, bem feito.

Estudar a aula: Seu ambiente e o Playground do curso

Módulo 2: Compreensões de lista, dicionário e conjunto

Questão 4 · aula O que é uma compreensão de lista

Qual compreensão produz a lista dos quadrados de [1, 2, 3, 4]?

  1. [n for n in range(4)]
  2. [n * n for n in [1, 2, 3, 4]]
  3. [n * n in [1, 2, 3, 4]]
  4. (n * n for n in [1, 2, 3, 4])
Ver a resposta

Resposta: B. [n * n for n in [1, 2, 3, 4]]

A forma é [expressão for item in sequência]. Aqui a expressão é n * n (o quadrado) e a sequência é [1, 2, 3, 4], resultando em [1, 4, 9, 16]. A terceira opção não tem o for e a quarta usa parênteses, que criam um generator, não uma lista.

Estudar a aula: O que é uma compreensão de lista

Questão 5 · aula Compreensão com condição

Você quer manter só os itens positivos de uma lista. Onde vai o if?

  1. No início, com else, antes do for.
  2. No fim, sem else, depois do for.
  3. Tanto faz, as duas formas filtram igual.
  4. Não dá para filtrar em compreensão, só transformar.
Ver a resposta

Resposta: B. No fim, sem else, depois do for.

Para filtrar (descartar itens), o if vai no fim, sem else: [n for n in lista if n > 0]. O if/else no início não filtra, ele escolhe o valor de cada item e mantém todos. As duas construções fazem coisas diferentes.

Estudar a aula: Compreensão com condição

Questão 6 · aula Compreensões aninhadas

Qual compreensão achata [[1, 2], [3, 4]] em [1, 2, 3, 4]?

  1. [linha for linha in matriz for item in linha]
  2. [item for item in linha for linha in matriz]
  3. [item for linha in matriz for item in linha]
  4. [[item for item in linha] for linha in matriz]
Ver a resposta

Resposta: C. [item for linha in matriz for item in linha]

Para achatar, a expressão é item (o valor de dentro), o for de fora percorre as linhas (for linha in matriz) e o de dentro percorre os itens de cada linha (for item in linha). A opção com dois colchetes recria a lista de listas em vez de achatar.

Estudar a aula: Compreensões aninhadas

Questão 7 · aula Compreensão de dicionário

Qual compreensão cria {"a": 1, "b": 2, "c": 3} a partir de letras = "abc"?

  1. [letra: i for i, letra in enumerate(letras, 1)]
  2. {letra for letra in letras}
  3. {letra: i for i, letra in enumerate(letras, 1)}
  4. {i: letra for i, letra in enumerate(letras, 1)}
Ver a resposta

Resposta: C. {letra: i for i, letra in enumerate(letras, 1)}

A compreensão de dicionário usa chaves e o par chave: valor. Com enumerate(letras, 1), i vai de 1 e letra recebe cada caractere; o par letra: i coloca a letra como chave e o número como valor. A primeira opção usa colchetes (inválido para dicionário) e a última inverte chave e valor.

Estudar a aula: Compreensão de dicionário

Questão 8 · aula Compreensão de conjunto e a espiada em generator

O que (n * 2 for n in [1, 2, 3]) cria?

  1. Uma tupla (2, 4, 6).
  2. Uma lista [2, 4, 6].
  3. Um generator, que produz os valores um a um quando consumido.
  4. Um conjunto {2, 4, 6}.
Ver a resposta

Resposta: C. Um generator, que produz os valores um a um quando consumido.

Parênteses em uma compreensão criam uma generator expression, não uma tupla. Ela não constrói nada na memória de imediato; produz cada valor sob demanda, quando algo a percorre (como sum ou um for). É a avaliação preguiçosa, aprofundada no módulo de geradores.

Estudar a aula: Compreensão de conjunto e a espiada em generator

Questão 9 · aula Prática: transformar dados de alunos

Qual compreensão cria um dicionário {nome: media} só dos alunos com media >= 7?

  1. [a["nome"]: a["media"] for a in dados if a["media"] >= 7]
  2. {a["nome"]: a["media"] for a in dados if a["media"] >= 7}
  3. {a["nome"] for a in dados if a["media"] >= 7}
  4. {a["media"]: a["nome"] for a in dados if a["media"] >= 7}
Ver a resposta

Resposta: B. {a["nome"]: a["media"] for a in dados if a["media"] >= 7}

É uma compreensão de dicionário (chaves e o par nome: media) com if no fim para filtrar quem tem média a partir de sete. A primeira usa colchetes (inválido para dicionário), a terceira cria um conjunto (sem par) e a quarta inverte chave e valor.

Estudar a aula: Prática: transformar dados de alunos

Módulo 3: Funções avançadas

Questão 10 · aula Parâmetros com valor padrão

Por que def formatar(moeda="BRL", valor) dá erro no Python?

  1. Porque moeda deveria ser um número, não um texto.
  2. Porque um parâmetro com valor padrão não pode vir antes de um parâmetro sem padrão.
  3. Porque o Python não aceita mais de um parâmetro por função.
  4. Porque valores padrão só funcionam com números.
Ver a resposta

Resposta: B. Porque um parâmetro com valor padrão não pode vir antes de um parâmetro sem padrão.

A regra é firme: parâmetros com valor padrão vêm sempre depois dos obrigatórios. Se um opcional viesse antes de um obrigatório, o Python não conseguiria casar os argumentos posicionais sem ambiguidade, então recusa o arquivo com SyntaxError.

Estudar a aula: Parâmetros com valor padrão

Questão 11 · aula Argumentos nomeados e posicionais

Qual é a principal vantagem de usar argumentos nomeados na chamada?

  1. A função roda mais rápido.
  2. A chamada fica mais clara, pois cada valor mostra a qual parâmetro pertence.
  3. Permite passar mais argumentos do que os parâmetros definidos.
  4. Elimina a necessidade de definir a função.
Ver a resposta

Resposta: B. A chamada fica mais clara, pois cada valor mostra a qual parâmetro pertence.

Argumentos nomeados casam pelo nome do parâmetro, então a chamada mostra o papel de cada valor e a ordem deixa de importar. Isso é ótimo para legibilidade, principalmente com True, False e números soltos, que sem nome não dizem nada.

Estudar a aula: Argumentos nomeados e posicionais

Questão 12 · aula *args e **kwargs: quantidade variável

Dentro de uma função, o que é o parâmetro *args?

  1. Um dicionário com os argumentos nomeados.
  2. Uma tupla com todos os argumentos posicionais extras recebidos.
  3. Uma lista fixa de exatamente dois valores.
  4. Uma cópia dos parâmetros com valor padrão.
Ver a resposta

Resposta: B. Uma tupla com todos os argumentos posicionais extras recebidos.

O asterisco recolhe todos os argumentos posicionais extras em uma tupla, por convenção chamada args. Você pode percorrê-la com um laço, medir com len e indexar. Os nomeados extras ficam em **kwargs, que é um dicionário.

Estudar a aula: *args e **kwargs: quantidade variável

Questão 13 · aula A armadilha do padrão mutável

Por que usar lista=None em vez de lista=[] como valor padrão?

  1. Porque None ocupa menos memória que uma lista.
  2. Porque o padrão é criado uma vez só; com [] todas as chamadas compartilham a mesma lista, e com None cada chamada cria a sua.
  3. Porque o Python não aceita listas como valor padrão.
  4. Porque None deixa a função mais rápida.
Ver a resposta

Resposta: B. Porque o padrão é criado uma vez só; com [] todas as chamadas compartilham a mesma lista, e com None cada chamada cria a sua.

O valor padrão é avaliado uma única vez, na definição. Uma lista vazia como padrão é compartilhada entre todas as chamadas, então os dados vazam. Usando None e criando a lista dentro da função com um if lista is None, cada chamada ganha um objeto novo.

Estudar a aula: A armadilha do padrão mutável

Questão 14 · aula Escopo local e global

Uma variável criada dentro de uma função, sem usar global, pode ser lida fora dela?

  1. Sim, toda variável é global por padrão.
  2. Não, ela é local e deixa de existir quando a função termina.
  3. Só se ela for um número.
  4. Só se a função for chamada duas vezes.
Ver a resposta

Resposta: B. Não, ela é local e deixa de existir quando a função termina.

Variáveis criadas dentro de uma função são locais: existem apenas durante a execução da função e somem quando ela retorna. Tentar usá-las fora gera NameError. Para compartilhar um valor, devolva-o com return em vez de depender de escopo global.

Estudar a aula: Escopo local e global

Questão 15 · aula Funções lambda e prática do módulo

Qual afirmação sobre funções lambda está correta?

  1. Lambda é sempre mais rápida que uma função com def.
  2. Lambda é uma função anônima de uma expressão, ideal para lógica curta usada de passagem, como o key de sorted.
  3. Lambda pode ter várias linhas com if e laços dentro.
  4. Lambda substitui def em qualquer situação.
Ver a resposta

Resposta: B. Lambda é uma função anônima de uma expressão, ideal para lógica curta usada de passagem, como o key de sorted.

A lambda é uma função anônima de uma única expressão, cujo valor é devolvido sem return. Ela serve para lógica trivial usada de passagem, como o critério de um sorted. Para lógica com if, laços ou várias linhas, ou que vá se repetir, o certo é usar def.

Estudar a aula: Funções lambda e prática do módulo

Módulo 4: Funções como objetos

Questão 16 · aula Funções são valores

Qual a diferença entre escrever dobrar e dobrar(3)?

  1. Não há diferença, os dois executam a função.
  2. dobrar aponta para o objeto função sem executá-lo; dobrar(3) executa a função com o argumento 3.
  3. dobrar dá erro; só dobrar(3) é válido no Python.
  4. dobrar executa a função e dobrar(3) apenas a referencia.
Ver a resposta

Resposta: B. dobrar aponta para o objeto função sem executá-lo; dobrar(3) executa a função com o argumento 3.

Sem parênteses, o nome apenas aponta para o objeto função, que pode ser guardado numa variável, lista ou dicionário. Com parênteses e argumentos, a função é executada e devolve um resultado. Essa distinção é a base de tratar funções como valores.

Estudar a aula: Funções são valores

Questão 17 · aula Funções de ordem superior

O que caracteriza uma função de ordem superior?

  1. Ser uma função que roda mais rápido que as outras.
  2. Ser uma função definida dentro de uma classe.
  3. Receber outra função como argumento ou devolver uma função como resultado.
  4. Ser uma função que só usa a biblioteca padrão.
Ver a resposta

Resposta: C. Receber outra função como argumento ou devolver uma função como resultado.

Função de ordem superior é a que recebe ao menos uma função como argumento ou devolve uma função como resultado. Isso separa a parte fixa (a estrutura) da parte que varia (o comportamento passado de fora), reduzindo repetição.

Estudar a aula: Funções de ordem superior

Questão 18 · aula Ordenar com key

Como ordenar uma lista de dicionários pessoas pela idade, de forma crescente?

  1. sorted(pessoas, key=idade)
  2. sorted(pessoas, lambda p: p['idade'])
  3. sorted(pessoas, key=lambda p: p['idade'])
  4. pessoas.sorted(key='idade')
Ver a resposta

Resposta: C. sorted(pessoas, key=lambda p: p['idade'])

O parâmetro key recebe uma função. A lambda lambda p: p['idade'] recebe cada pessoa e devolve a idade, que vira o critério de comparação. key precisa ser nomeado, e a função vai sem parênteses.

Estudar a aula: Ordenar com key

Questão 19 · aula map e filter

Para dobrar os números pares de uma lista, qual costuma ser a escrita mais clara?

  1. list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, nums)))
  2. [x * 2 for x in nums if x % 2 == 0]
  3. map(x * 2 for x in nums)
  4. filter(nums, x % 2 == 0)
Ver a resposta

Resposta: B. [x * 2 for x in nums if x % 2 == 0]

A compreensão de lista [x * 2 for x in nums if x % 2 == 0] junta o filtro e a transformação em uma expressão legível, sem lambdas aninhadas nem list() em volta. É a forma preferida na maioria dos casos que map e filter também resolvem.

Estudar a aula: map e filter

Questão 20 · aula Closures

O que é um closure no Python?

  1. Uma função que roda automaticamente ao final do programa.
  2. Uma função interna que continua lembrando as variáveis da função externa, mesmo depois de ela terminar.
  3. Uma forma de fechar o programa liberando memória.
  4. Uma função que só pode ser chamada uma vez.
Ver a resposta

Resposta: B. Uma função interna que continua lembrando as variáveis da função externa, mesmo depois de ela terminar.

Closure é a função interna que fecha ao redor das variáveis da função externa e as mantém vivas enquanto existir, mesmo depois de a externa terminar. É o que faz uma fábrica como criar_multiplicador gerar funções que lembram o próprio fator.

Estudar a aula: Closures

Questão 21 · aula Prática: ordenar e transformar

Para ordenar alunos pela maior nota e, no empate, pelo nome em ordem alfabética, o que passar em key?

  1. key=lambda a: a['nota'], reverse=True
  2. key=lambda a: (-a['nota'], a['nome'])
  3. key=lambda a: a['nome'], a['nota']
  4. key=(a['nota'], a['nome'])
Ver a resposta

Resposta: B. key=lambda a: (-a['nota'], a['nome'])

Devolver a tupla (-a['nota'], a['nome']) faz a nota ser comparada do maior para o menor (por causa do sinal de menos) e, nos empates, usa o nome em ordem alfabética crescente. Uma tupla no key permite misturar critérios decrescentes e crescentes.

Estudar a aula: Prática: ordenar e transformar

Módulo 5: Módulos e a biblioteca padrão

Questão 22 · aula O que é um módulo e como o import funciona

Qual a diferença entre import math e from math import sqrt?

  1. Nenhuma, os dois fazem exatamente a mesma coisa.
  2. import math traz o módulo inteiro (usado como math.sqrt); from math import sqrt traz só sqrt, usado direto.
  3. from math import sqrt é mais rápido em todos os casos.
  4. import math só funciona no Playground e from import só no computador.
Ver a resposta

Resposta: B. import math traz o módulo inteiro (usado como math.sqrt); from math import sqrt traz só sqrt, usado direto.

import math traz o módulo todo e você acessa cada função pelo prefixo, como math.sqrt. Já from math import sqrt traz apenas a função sqrt para o seu código, usada direto, sem o prefixo. O import com prefixo costuma ser preferido por deixar clara a origem de cada nome.

Estudar a aula: O que é um módulo e como o import funciona

Questão 23 · aula Criando seu próprio módulo

Para que serve o if __name__ == "__main__" em um módulo?

  1. Para o módulo rodar mais rápido quando importado.
  2. Para separar o código que só deve rodar ao executar o arquivo direto do que deve rodar ao importá-lo.
  3. É obrigatório em todo arquivo Python, senão dá erro.
  4. Para transformar funções em classes automaticamente.
Ver a resposta

Resposta: B. Para separar o código que só deve rodar ao executar o arquivo direto do que deve rodar ao importá-lo.

A variável __name__ vale "__main__" quando o arquivo é executado direto, e vale o nome do módulo quando é importado. O if usa essa diferença para rodar testes e o ponto de entrada apenas na execução direta, mantendo o módulo limpo para quem o importa.

Estudar a aula: Criando seu próprio módulo

Questão 24 · aula Matemática e sorte: math e random

Qual função escolhe um item aleatório de uma lista já existente?

  1. random.randint(lista)
  2. random.choice(lista)
  3. random.random(lista)
  4. math.floor(lista)
Ver a resposta

Resposta: B. random.choice(lista)

random.choice(lista) devolve um item aleatório da lista informada. A randint sorteia um inteiro num intervalo numérico, a random devolve um decimal entre 0 e 1 sem argumentos, e o math.floor arredonda um número para baixo, nada a ver com escolher itens.

Estudar a aula: Matemática e sorte: math e random

Questão 25 · aula Trabalhando com datas: datetime em visão geral

O que você recebe ao subtrair uma data de outra no Python?

  1. Um número inteiro com a quantidade de dias, direto.
  2. Um objeto timedelta, do qual você tira os dias com o atributo .days.
  3. Um texto no formato dia/mês/ano.
  4. Um erro, porque não dá para subtrair datas.
Ver a resposta

Resposta: B. Um objeto timedelta, do qual você tira os dias com o atributo .days.

Subtrair duas datas devolve um objeto timedelta, que representa uma duração. Para obter a diferença em dias, use o atributo .days desse timedelta, como em (ano_novo - hoje).days. Ele não devolve um número solto nem um texto.

Estudar a aula: Trabalhando com datas: datetime em visão geral

Questão 26 · aula Coleções especiais: Counter, defaultdict e namedtuple

Qual coleção do módulo collections conta ocorrências automaticamente?

  1. namedtuple, que conta os campos nomeados.
  2. Counter, que recebe uma sequência e devolve quantas vezes cada item aparece.
  3. defaultdict, que existe só para agrupar em listas.
  4. Nenhuma; contar exige sempre um laço manual.
Ver a resposta

Resposta: B. Counter, que recebe uma sequência e devolve quantas vezes cada item aparece.

O Counter recebe uma sequência e já devolve um dicionário com a contagem de cada item, além de métodos como most_common para pegar os mais frequentes. O defaultdict evita o KeyError e o namedtuple dá nomes aos campos de uma tupla, cada um com outro propósito.

Estudar a aula: Coleções especiais: Counter, defaultdict e namedtuple

Questão 27 · aula Prática: um utilitário com Counter e random

No utilitário final, por que a demonstração ficou dentro do if __name__ == "__main__"?

  1. Para o arquivo rodar mais rápido.
  2. Para que os prints de demonstração rodem só ao executar o arquivo direto, e não quando outro programa importar as funções.
  3. Porque Counter e random exigem esse bloco para funcionar.
  4. Para transformar as funções em classes.
Ver a resposta

Resposta: B. Para que os prints de demonstração rodem só ao executar o arquivo direto, e não quando outro programa importar as funções.

O bloco sob o if __name__ == "__main__" só roda quando o arquivo é executado diretamente. Assim, a demonstração aparece ao rodar o arquivo, mas quem importa o módulo recebe apenas as funções contar_palavras e palavra_do_dia, sem os prints de teste atrapalhando.

Estudar a aula: Prática: um utilitário com Counter e random

Módulo 6: Ambientes virtuais e pip

Questão 28 · aula Por que ambientes virtuais existem

Qual problema o ambiente virtual resolve de forma direta?

  1. Deixa o Python rodar mais rápido.
  2. Permite que projetos diferentes usem versões diferentes do mesmo pacote sem conflito.
  3. Substitui a necessidade de instalar o Python.
  4. Dispensa o uso do pip para instalar pacotes.
Ver a resposta

Resposta: B. Permite que projetos diferentes usem versões diferentes do mesmo pacote sem conflito.

O ambiente virtual dá a cada projeto uma despensa isolada de pacotes. Assim, um projeto pode usar a versão 1 de uma biblioteca e outro a versão 2 ao mesmo tempo, sem que a instalação de um quebre o outro.

Estudar a aula: Por que ambientes virtuais existem

Questão 29 · aula Criando um ambiente virtual no Windows

Você abriu um terminal novo e o pacote do projeto some. O mais provável é que:

  1. A pasta .venv foi apagada sozinha.
  2. Você esqueceu de ativar o ambiente virtual naquela nova sessão de terminal.
  3. O pip está com defeito e precisa ser reinstalado.
  4. O Python global foi desinstalado.
Ver a resposta

Resposta: B. Você esqueceu de ativar o ambiente virtual naquela nova sessão de terminal.

A ativação vale apenas para a janela de terminal atual. Ao abrir um terminal novo, você precisa rodar .venv\Scripts\activate de novo. Sem o prefixo (.venv), os comandos usam o Python global, que não enxerga os pacotes do projeto.

Estudar a aula: Criando um ambiente virtual no Windows

Questão 30 · aula Instalando pacotes com pip

Você rodou pip install requests, mas com o ambiente virtual desativado. O que acontece?

  1. O comando falha, porque o pip só funciona com ambiente ativo.
  2. O requests é instalado na instalação global do Python, e não na despensa do projeto.
  3. O pacote é instalado nos dois lugares ao mesmo tempo.
  4. Nada; o pip ignora o comando fora do ambiente.
Ver a resposta

Resposta: B. O requests é instalado na instalação global do Python, e não na despensa do projeto.

Sem o (.venv) ativo, o pip usa a instalação global. O requests iria para lá, não para a despensa do projeto. Por isso vale conferir o prefixo (.venv) no terminal antes de instalar, e usar pip list para confirmar onde o pacote foi parar.

Estudar a aula: Instalando pacotes com pip

Questão 31 · aula requirements.txt: a receita do projeto

Para que serve o comando pip install -r requirements.txt?

  1. Para criar o ambiente virtual do projeto.
  2. Para instalar de uma vez todos os pacotes listados no arquivo, nas versões indicadas.
  3. Para apagar os pacotes que não estão no arquivo.
  4. Para atualizar o pip para a versão mais nova.
Ver a resposta

Resposta: B. Para instalar de uma vez todos os pacotes listados no arquivo, nas versões indicadas.

O -r aponta para um arquivo de requisitos. O pip lê o requirements.txt e instala cada pacote na versão travada ali, recriando a mesma despensa. É o que torna o projeto reprodutível em qualquer computador.

Estudar a aula: requirements.txt: a receita do projeto

Questão 32 · aula Usando um pacote externo na prática

No exemplo, o que o método resposta.json() faz?

  1. Envia o pedido para a API pela primeira vez.
  2. Converte o corpo JSON da resposta em dados Python, como um dicionário.
  3. Confere o código de status da resposta.
  4. Salva a resposta em um arquivo no disco.
Ver a resposta

Resposta: B. Converte o corpo JSON da resposta em dados Python, como um dicionário.

O pedido já foi feito por requests.get. O resposta.json() apenas lê o corpo da resposta, que veio em JSON, e o transforma em dados Python (em geral um dicionário ou lista), para você acessar os valores por chave.

Estudar a aula: Usando um pacote externo na prática

Questão 33 · aula Prática: montar um projeto isolado

Na ordem do fluxo profissional, o que vem logo depois de criar o ambiente virtual?

  1. Rodar o script principal do projeto.
  2. Ativar o ambiente, para que python e pip passem a usar a despensa do projeto.
  3. Gerar o requirements.txt antes de instalar qualquer pacote.
  4. Apagar a pasta .venv para começar limpo.
Ver a resposta

Resposta: B. Ativar o ambiente, para que python e pip passem a usar a despensa do projeto.

Criar o ambiente não basta: é preciso ativá-lo com .venv\Scripts\activate para que os comandos usem a despensa isolada. Só depois de ativo você instala os pacotes, congela a receita e roda o script.

Estudar a aula: Prática: montar um projeto isolado

Módulo 7: Trabalhando com JSON

Questão 34 · aula O que é JSON e por que ele está em todo lugar

Qual afirmação sobre a relação entre JSON e Python está correta?

  1. JSON só funciona com programas escritos em JavaScript.
  2. Um objeto JSON lembra um dicionário e uma lista JSON lembra uma lista, mas o nulo é null e não None.
  3. JSON e Python usam exatamente a mesma grafia para tudo, sem nenhuma diferença.
  4. JSON substitui os dicionários do Python e não pode ser convertido de volta.
Ver a resposta

Resposta: B. Um objeto JSON lembra um dicionário e uma lista JSON lembra uma lista, mas o nulo é null e não None.

JSON é muito parecido com as estruturas do Python: objetos lembram dicionários e arrays lembram listas. As diferenças são de grafia, como true/false em minúsculas e null no lugar de None. E dá para converter nos dois sentidos com o módulo json.

Estudar a aula: O que é JSON e por que ele está em todo lugar

Questão 35 · aula De Python para JSON com json.dumps

Você converte um dicionário com o nome "São Paulo" e o resultado mostra "S\u00e3o Paulo". O que faltou?

  1. Passar indent=2 no json.dumps.
  2. Passar ensure_ascii=False no json.dumps para preservar os acentos.
  3. Trocar json.dumps por json.loads.
  4. Remover o acento do dicionário antes de converter.
Ver a resposta

Resposta: B. Passar ensure_ascii=False no json.dumps para preservar os acentos.

Por padrão, ensure_ascii vale True e escapa acentos como \u00e3. Passando ensure_ascii=False, o São Paulo aparece legível. O indent só cuida da indentação, não dos acentos, e trocar por loads faria o caminho contrário.

Estudar a aula: De Python para JSON com json.dumps

Questão 36 · aula De JSON para Python com json.loads

Você recebe a resposta de uma API como texto e quer acessar os campos no Python. Qual função usar?

  1. json.dumps, porque produz um dicionário.
  2. json.loads, que transforma a string JSON em dicionário ou lista do Python.
  3. json.dump, que grava o texto em um arquivo.
  4. print, que já converte JSON em dados automaticamente.
Ver a resposta

Resposta: B. json.loads, que transforma a string JSON em dicionário ou lista do Python.

Para ir de texto JSON para dados do Python usa-se json.loads. O dumps faz o contrário (dados para texto), o dump grava em arquivo e o print apenas exibe. Depois do loads, você acessa os campos como em qualquer dicionário ou lista.

Estudar a aula: De JSON para Python com json.loads

Questão 37 · aula Lendo e gravando arquivos JSON

Ao gravar e ler um arquivo JSON com nomes acentuados, qual cuidado evita acentos embaralhados?

  1. Usar json.dumps em vez de json.dump.
  2. Abrir o arquivo com encoding="utf-8" tanto na escrita quanto na leitura.
  3. Remover todos os acentos antes de gravar.
  4. Gravar sempre em uma única linha, sem indent.
Ver a resposta

Resposta: B. Abrir o arquivo com encoding="utf-8" tanto na escrita quanto na leitura.

Passar encoding="utf-8" ao abrir o arquivo para escrever e para ler garante que os acentos sejam gravados e recuperados corretamente, sem depender do padrão do sistema operacional. O indent e o ensure_ascii ajudam na legibilidade, mas o encoding é o que resolve o encoding do arquivo em si.

Estudar a aula: Lendo e gravando arquivos JSON

Questão 38 · aula Dados aninhados: listas dentro de dicionários

Em dados["pedidos"][0]["valor"], o que cada parte faz, na ordem?

  1. Pega o valor, depois o pedido, depois a lista.
  2. Pega a lista de pedidos, depois o primeiro pedido, depois o campo valor desse pedido.
  3. Cria uma lista chamada pedidos com um item de valor zero.
  4. Converte o JSON em texto antes de acessar o valor.
Ver a resposta

Resposta: B. Pega a lista de pedidos, depois o primeiro pedido, depois o campo valor desse pedido.

A leitura é da esquerda para a direita, descendo uma camada por colchete: dados["pedidos"] pega a lista, [0] pega o primeiro item (um dicionário) e ["valor"] pega o campo valor dele. É assim que se navega em JSON aninhado.

Estudar a aula: Dados aninhados: listas dentro de dicionários

Questão 39 · aula Prática: um catálogo de produtos em JSON

Na prática do catálogo, por que os acentos de Acessórios e Eletrônicos apareceram corretos no arquivo e na leitura?

  1. Porque o JSON remove acentos automaticamente e os recoloca.
  2. Porque foram usados ensure_ascii=False ao gravar e encoding="utf-8" ao abrir o arquivo nas duas pontas.
  3. Porque o json.load conserta qualquer acento sozinho.
  4. Porque a lista de dicionários não permite acentos errados.
Ver a resposta

Resposta: B. Porque foram usados ensure_ascii=False ao gravar e encoding="utf-8" ao abrir o arquivo nas duas pontas.

O ensure_ascii=False manteve os acentos legíveis no texto JSON, e o encoding="utf-8" na escrita e na leitura garantiu que o arquivo fosse gravado e recuperado sem embaralhar os caracteres. Essa dupla é o que preserva o português nos arquivos JSON.

Estudar a aula: Prática: um catálogo de produtos em JSON

Módulo 8: Arquivos CSV e pathlib

Questão 40 · aula O que é CSV

O que melhor descreve um arquivo CSV?

  1. Um formato binário que só o Excel consegue abrir.
  2. Uma tabela guardada como texto puro, com uma linha por registro e campos separados por vírgula ou ponto e vírgula.
  3. Um tipo de imagem usado em planilhas.
  4. Um banco de dados com senha e índices internos.
Ver a resposta

Resposta: B. Uma tabela guardada como texto puro, com uma linha por registro e campos separados por vírgula ou ponto e vírgula.

CSV é texto puro: cada linha é um registro e os campos vêm separados por um caractere, quase sempre vírgula ou ponto e vírgula. Por ser texto simples, qualquer programa abre, o que o tornou o formato de troca mais comum.

Estudar a aula: O que é CSV

Questão 41 · aula Lendo CSV

Qual a principal vantagem de usar csv.DictReader em vez de csv.reader?

  1. Ele lê o arquivo mais rápido que o reader.
  2. Ele acessa os campos pelo nome da coluna, em vez de pela posição, ficando mais claro e resistente a mudanças de ordem.
  3. Ele converte os números automaticamente para float.
  4. Ele dispensa o with open na abertura do arquivo.
Ver a resposta

Resposta: B. Ele acessa os campos pelo nome da coluna, em vez de pela posição, ficando mais claro e resistente a mudanças de ordem.

O DictReader usa o cabeçalho como chaves e entrega dicionários, então você acessa linha['nota'] pelo nome. É mais legível e não quebra se a ordem das colunas mudar. Ele não converte números sozinho: a conversão com float continua sendo sua.

Estudar a aula: Lendo CSV

Questão 42 · aula Gravando CSV

Por que gravar um CSV com encoding='utf-8-sig' quando ele será aberto no Excel em português?

  1. Porque utf-8-sig deixa o arquivo menor.
  2. Porque ele adiciona uma marca (BOM) que o Excel reconhece, fazendo os acentos aparecerem corretamente.
  3. Porque o Python só grava acentos com utf-8-sig.
  4. Porque o Excel não abre arquivos gravados em utf-8 comum.
Ver a resposta

Resposta: B. Porque ele adiciona uma marca (BOM) que o Excel reconhece, fazendo os acentos aparecerem corretamente.

O Excel em português não assume utf-8 por padrão ao abrir CSV, então acentos podem sair errados. O utf-8-sig adiciona uma marca invisível (BOM) no início que o Excel reconhece, exibindo São Paulo e outros acentos corretamente. O Python lê os dois formatos sem problema.

Estudar a aula: Gravando CSV

Questão 43 · aula pathlib: caminhos modernos

Por que usar Path('dados') / 'vendas.csv' é melhor que 'dados' + '/' + 'vendas.csv'?

  1. Porque o operador barra é mais rápido que somar textos.
  2. Porque o Path junta as partes com o separador correto de cada sistema e evita erros de barra faltando ou repetida.
  3. Porque não é possível somar textos em Python.
  4. Porque o Path grava o arquivo automaticamente ao juntar.
Ver a resposta

Resposta: B. Porque o Path junta as partes com o separador correto de cada sistema e evita erros de barra faltando ou repetida.

Somar textos exige acertar as barras na mão e usa sempre a barra normal, o que quebra no Windows, que usa contrabarra. O operador barra do Path junta as partes com o separador certo de cada sistema e produz um objeto que ainda sabe consultar name, suffix e exists.

Estudar a aula: pathlib: caminhos modernos

Questão 44 · aula Context managers: o with a fundo

Por que o with é preferido a chamar close na mão ao trabalhar com arquivos?

  1. Porque o with lê o arquivo mais rápido.
  2. Porque o with fecha o arquivo automaticamente ao sair do bloco, inclusive quando ocorre um erro no meio do processamento.
  3. Porque sem o with não é possível ler arquivos.
  4. Porque o with dispensa informar o encoding.
Ver a resposta

Resposta: B. Porque o with fecha o arquivo automaticamente ao sair do bloco, inclusive quando ocorre um erro no meio do processamento.

O with garante o fechamento ao sair do bloco, mesmo se um erro estourar no meio, equivalendo a um try/finally sem você escrevê-lo. Chamar close na mão é frágil: um erro pularia o close e deixaria o arquivo aberto. Por isso o with é o jeito recomendado.

Estudar a aula: Context managers: o with a fundo

Questão 45 · aula Prática: relatório de vendas em CSV

No relatório, para que serve totais.get(categoria, 0.0) ao somar por categoria?

  1. Para converter o valor de texto para número.
  2. Para devolver o total já acumulado da categoria, ou zero se ela aparece pela primeira vez, evitando erro na chave nova.
  3. Para ordenar as categorias do maior para o menor.
  4. Para gravar o resumo no arquivo de saída.
Ver a resposta

Resposta: B. Para devolver o total já acumulado da categoria, ou zero se ela aparece pela primeira vez, evitando erro na chave nova.

O get devolve o valor atual da chave ou o segundo argumento (0.0) quando a chave ainda não existe. Assim, ao encontrar uma categoria pela primeira vez, o acumulador começa do zero sem quebrar, e nas próximas vezes soma sobre o total já guardado. É o jeito pythônico de acumular em dicionário.

Estudar a aula: Prática: relatório de vendas em CSV

Módulo 9: Erros e exceções: nível avançado

Questão 46 · aula Relembrando try e except

Por que capturar ValueError é melhor que usar um except genérico?

  1. Porque except genérico não funciona no Python 3.
  2. Porque o tipo específico trata só o erro previsto e deixa os imprevistos aparecerem para conserto.
  3. Porque ValueError é mais rápido de processar.
  4. Porque o except genérico só funciona dentro de funções.
Ver a resposta

Resposta: B. Porque o tipo específico trata só o erro previsto e deixa os imprevistos aparecerem para conserto.

Capturar o tipo específico trata apenas a falha que você já esperava. Um except genérico engoliria também erros imprevistos, como um NameError de digitação, mostrando a mensagem errada e escondendo o bug real.

Estudar a aula: Relembrando try e except

Questão 47 · aula Os blocos else e finally

Em quais situações o bloco finally é executado?

  1. Somente quando o try levanta uma exceção.
  2. Somente quando o try termina sem erro.
  3. Sempre ao sair do try, tenha havido exceção ou não.
  4. Apenas quando existe um bloco else no mesmo try.
Ver a resposta

Resposta: C. Sempre ao sair do try, tenha havido exceção ou não.

O finally executa em qualquer saída do try: com erro, sem erro e até quando há um return. Por isso é o lugar certo para liberar recursos, como fechar um arquivo, com a garantia de que a limpeza sempre acontece.

Estudar a aula: Os blocos else e finally

Questão 48 · aula Levantando erros com raise

Quando faz sentido usar raise ValueError dentro de uma função?

  1. Sempre que a função termina normalmente e devolve um resultado.
  2. Quando o valor recebido é inadequado e não dá para continuar com segurança.
  3. Apenas dentro de um bloco except já existente.
  4. Para deixar a função rodar mais rápido.
Ver a resposta

Resposta: B. Quando o valor recebido é inadequado e não dá para continuar com segurança.

O raise sinaliza que um valor recebido não faz sentido, como um percentual fora de 0 a 100. Em vez de devolver um resultado inválido ou None, a função para e explica o problema, de preferência com o valor recebido na mensagem.

Estudar a aula: Levantando erros com raise

Questão 49 · aula Criando exceções próprias

Qual é o jeito correto de definir uma exceção própria no Python?

  1. def SaldoInsuficienteError(): pass
  2. class SaldoInsuficienteError(Exception): pass
  3. raise SaldoInsuficienteError = Exception
  4. SaldoInsuficienteError = ValueError()
Ver a resposta

Resposta: B. class SaldoInsuficienteError(Exception): pass

Uma exceção própria é uma classe que herda de Exception. O corpo pode ser apenas pass ou um docstring; a herança já fornece todo o comportamento. Depois você a levanta com raise e a captura com except pelo nome.

Estudar a aula: Criando exceções próprias

Questão 50 · aula Encadeamento e boas práticas

Por que um except vazio com pass é considerado um antipadrão?

  1. Porque o Python 3 não permite except sem tipo.
  2. Porque ele engole qualquer erro em silêncio, escondendo bugs que deveriam ser corrigidos.
  3. Porque deixa o programa muito mais lento.
  4. Porque só funciona fora de funções.
Ver a resposta

Resposta: B. Porque ele engole qualquer erro em silêncio, escondendo bugs que deveriam ser corrigidos.

O except vazio captura tudo e, com pass, ignora tudo em silêncio. Isso esconde falhas inesperadas, inclusive bugs do seu código, e um erro silencioso é pior que uma quebra, porque não avisa. Prefira capturar o tipo específico que você sabe tratar.

Estudar a aula: Encadeamento e boas práticas

Questão 51 · aula Prática: validação robusta de um saque

Por que a função sacar valida o valor antes de calcular o novo saldo?

  1. Para o código rodar mais rápido.
  2. Para falhar cedo e nunca alterar o saldo com base em um dado inválido.
  3. Porque o Python exige validação no início de toda função.
  4. Para evitar o uso de except no programa que chama.
Ver a resposta

Resposta: B. Para falhar cedo e nunca alterar o saldo com base em um dado inválido.

Validar antes de alterar o estado é falhar cedo: se o valor é inválido, a função levanta a exceção sem tocar no saldo. Isso mantém a invariante de que o saldo nunca fica corrompido por uma entrada ruim, e a mensagem aponta o problema na origem.

Estudar a aula: Prática: validação robusta de um saque

Módulo 10: Orientação a objetos: classes

Questão 52 · aula O que é orientação a objetos

Na analogia da confeitaria, o que representa a classe e o que representa o objeto?

  1. A classe é o bolo pronto e o objeto é a forma que o moldou.
  2. A classe é a forma de bolo (o molde) e cada objeto é um bolo feito a partir dela.
  3. Classe e objeto são a mesma coisa, só muda o nome.
  4. A classe é o recheio e o objeto é a cobertura do bolo.
Ver a resposta

Resposta: B. A classe é a forma de bolo (o molde) e cada objeto é um bolo feito a partir dela.

A classe é o molde, como a forma de bolo: define o formato sem ser a coisa em si. Cada objeto (ou instância) é um bolo feito a partir da forma, com os seus próprios dados. Da mesma forma se cria a conta da Ana e a do Bruno a partir de uma classe ContaBancaria.

Estudar a aula: O que é orientação a objetos

Questão 53 · aula Criando uma classe

Qual linha cria um novo objeto a partir da classe Conta?

  1. class Conta:
  2. conta = Conta
  3. conta = Conta()
  4. print(Conta)
Ver a resposta

Resposta: C. conta = Conta()

Criar um objeto (instanciar) é chamar o nome da classe seguido de parênteses: conta = Conta(). Sem os parênteses, conta = Conta apenas dá outro nome à própria classe, não cria um objeto. class Conta: define o molde, e print só o exibe.

Estudar a aula: Criando uma classe

Questão 54 · aula O método __init__ e o self

Quando o método __init__ é executado?

  1. Toda vez que você acessa um atributo do objeto.
  2. Automaticamente, no momento em que você cria o objeto com Conta(...).
  3. Só quando você chama conta.__init__() à mão.
  4. Uma vez por classe, quando o programa começa.
Ver a resposta

Resposta: B. Automaticamente, no momento em que você cria o objeto com Conta(...).

O __init__ é o construtor: o Python o chama sozinho no instante em que você cria o objeto, como em Conta('Ana', 500). Ele prepara os atributos iniciais com self. Você não o chama manualmente; a criação do objeto já dispara o __init__.

Estudar a aula: O método __init__ e o self

Questão 55 · aula Métodos de instância

Na chamada conta.depositar(50), de onde vem o self dentro do método?

  1. Você precisa passar o self como primeiro argumento: conta.depositar(conta, 50).
  2. O self é o objeto antes do ponto (conta), e o Python o entrega automaticamente.
  3. O self é sempre o número 50 passado na chamada.
  4. O self só existe dentro do __init__, não nos outros métodos.
Ver a resposta

Resposta: B. O self é o objeto antes do ponto (conta), e o Python o entrega automaticamente.

Na chamada conta.depositar(50), o objeto antes do ponto (conta) vira o self dentro do método, entregue pelo Python sozinho. Você informa só o valor (50). Por isso o método tem dois parâmetros (self e valor), mas a chamada passa apenas um.

Estudar a aula: Métodos de instância

Questão 56 · aula Atributos de classe e de instância

Por que declarar uma lista como atributo de classe costuma dar problema?

  1. Porque listas não podem ser atributos em Python.
  2. Porque existe uma cópia só, dividida por todos os objetos, então mudar em um afeta os outros.
  3. Porque o Python cria uma lista nova para cada objeto automaticamente.
  4. Porque listas de classe deixam o programa mais lento.
Ver a resposta

Resposta: B. Porque existe uma cópia só, dividida por todos os objetos, então mudar em um afeta os outros.

Um atributo de classe é compartilhado: há uma cópia só, ligada à classe. Uma lista ali é a mesma para todos os objetos, então adicionar um item por um objeto aparece nos demais. Para uma lista própria por objeto, crie-a no __init__ com self.movimentos = [].

Estudar a aula: Atributos de classe e de instância

Questão 57 · aula O método __str__

O que o método __str__ deve fazer no seu corpo?

  1. Imprimir o objeto na tela com print.
  2. Retornar uma string com o texto amigável do objeto.
  3. Alterar os atributos do objeto antes de exibir.
  4. Chamar o __init__ de novo para recriar o objeto.
Ver a resposta

Resposta: B. Retornar uma string com o texto amigável do objeto.

O __str__ deve retornar (return) uma string com o texto amigável do objeto, sem imprimir. Quem imprime é o print, que chama o __str__ para obter a frase. Usar print dentro do __str__, ou esquecer o return, é o erro mais comum.

Estudar a aula: O método __str__

Questão 58 · aula Prática: a classe ContaBancaria

Na classe ContaBancaria, por que a validação do saque fica dentro do método sacar?

  1. Por acaso; poderia ficar em qualquer lugar sem diferença.
  2. Para que toda tentativa de saque passe pela mesma regra, mantendo o saldo sempre válido.
  3. Porque o Python obriga colocar if dentro de todo método.
  4. Para deixar o método sacar mais longo e completo.
Ver a resposta

Resposta: B. Para que toda tentativa de saque passe pela mesma regra, mantendo o saldo sempre válido.

Colocar a regra dentro do método sacar (encapsular) garante que todo saque, venha de onde vier, passe pela mesma validação. Assim o objeto protege o próprio estado e o saldo nunca fica inválido, sem depender de quem chama lembrar da checagem.

Estudar a aula: Prática: a classe ContaBancaria

Módulo 11: Orientação a objetos: herança

Questão 59 · aula O que é herança

Qual relação justifica usar herança entre duas classes?

  1. A filha tem um objeto da base guardado dentro dela.
  2. As duas classes têm nomes parecidos.
  3. A filha é um tipo mais específico da base (relação é-um).
  4. As duas classes estão no mesmo arquivo.
Ver a resposta

Resposta: C. A filha é um tipo mais específico da base (relação é-um).

Herança modela a relação é-um: a filha é um tipo mais específico da base, como Cachorro é um Animal. Quando a relação é tem-um (a filha tem um objeto), o certo é composição, não herança. Nome parecido ou mesmo arquivo não justificam herdar.

Estudar a aula: O que é herança

Questão 60 · aula Criando uma classe filha

O que a linha class Carro(Veiculo): faz?

  1. Cria uma classe Carro sem nenhuma ligação com Veiculo.
  2. Faz Carro herdar os atributos e métodos de Veiculo.
  3. Copia o texto de Veiculo para dentro de Carro.
  4. Cria um objeto Carro a partir de Veiculo.
Ver a resposta

Resposta: B. Faz Carro herdar os atributos e métodos de Veiculo.

O nome entre parênteses indica a classe base. Assim, Carro herda os atributos e métodos de Veiculo, sem copiar código: eles continuam definidos em Veiculo e ficam acessíveis em Carro. A linha define uma classe, não cria um objeto.

Estudar a aula: Criando uma classe filha

Questão 61 · aula super() e o __init__ da base

Para que serve super().__init__() dentro do construtor da filha?

  1. Para criar um novo objeto da classe base.
  2. Para chamar o construtor da base e reaproveitar a inicialização dela.
  3. Para impedir que a filha tenha atributos próprios.
  4. Para copiar o código da base para a filha.
Ver a resposta

Resposta: B. Para chamar o construtor da base e reaproveitar a inicialização dela.

super().__init__() chama o construtor da classe base a partir da filha, deixando a base cuidar da parte da inicialização que já sabe fazer. Depois, a filha acrescenta os seus atributos próprios. Assim, a lógica comum mora só na base e não é duplicada.

Estudar a aula: super() e o __init__ da base

Questão 62 · aula Sobrescrever métodos

O que significa sobrescrever um método na classe filha?

  1. Apagar o método da classe base para sempre.
  2. Definir na filha um método com o mesmo nome da base, que passa a ser usado pelos objetos dela.
  3. Chamar o método da base sem mudá-lo.
  4. Criar um método com um nome diferente na filha.
Ver a resposta

Resposta: B. Definir na filha um método com o mesmo nome da base, que passa a ser usado pelos objetos dela.

Sobrescrever é redefinir na filha um método com o mesmo nome de um da base. Para os objetos da filha, o Python usa a versão dela. A base continua intacta para outras classes, e a filha pode até chamar a versão da base com super() para completá-la.

Estudar a aula: Sobrescrever métodos

Questão 63 · aula Polimorfismo na prática

Por que o laço que chama bicho.falar() não precisa de if por tipo?

  1. Porque todos os objetos são exatamente do mesmo tipo.
  2. Porque cada classe sobrescreve falar, então o Python já usa a versão certa para cada objeto.
  3. Porque o laço só funciona com um objeto de cada vez.
  4. Porque falar é um método privado.
Ver a resposta

Resposta: B. Porque cada classe sobrescreve falar, então o Python já usa a versão certa para cada objeto.

Como cada filha sobrescreve falar, chamar bicho.falar() faz o Python escolher a versão da classe daquele objeto. O laço não precisa saber o tipo; ele confia no método comum. Por isso adicionar um novo tipo não obriga a mudar o laço.

Estudar a aula: Polimorfismo na prática

Questão 64 · aula Encapsulamento

O que a convenção de um underscore no início do nome, como self._saldo, comunica?

  1. Que o Python proíbe totalmente o acesso a esse atributo.
  2. Que o atributo é interno e não deve ser acessado direto de fora, por convenção.
  3. Que o atributo é uma constante que nunca muda.
  4. Que o atributo é mais rápido de acessar.
Ver a resposta

Resposta: B. Que o atributo é interno e não deve ser acessado direto de fora, por convenção.

O underscore inicial é uma convenção: sinaliza que o atributo é interno e que se deve usar os métodos públicos, não acessá-lo direto. O Python não impede o acesso; é um acordo entre quem escreve o código. É a base do encapsulamento em Python.

Estudar a aula: Encapsulamento

Questão 65 · aula Prática: hierarquia de formas

Por que o laço que faz total += forma.area() funciona com retângulos e círculos misturados?

  1. Porque todas as formas têm a mesma área.
  2. Porque cada filha sobrescreve area() com a sua fórmula, e o laço só confia no método comum.
  3. Porque o laço verifica o tipo de cada forma com if antes de somar.
  4. Porque a classe Forma calcula a área de todas as filhas.
Ver a resposta

Resposta: B. Porque cada filha sobrescreve area() com a sua fórmula, e o laço só confia no método comum.

Retangulo e Circulo herdam de Forma e sobrescrevem area() cada um com a sua fórmula. O laço chama forma.area() sem checar o tipo; o Python usa a versão certa para cada objeto. É polimorfismo: por isso um novo tipo de forma entra na lista sem mudar o laço.

Estudar a aula: Prática: hierarquia de formas

Módulo 12: Decoradores

Questão 66 · aula O caminho até o decorador

O que a função com_moldura(func) devolve?

  1. O resultado de chamar func imediatamente.
  2. A função interna wrapper, sem chamá-la, para ser executada depois.
  3. O texto que func imprimiria.
  4. Uma cópia idêntica de func, sem nenhuma mudança.
Ver a resposta

Resposta: B. A função interna wrapper, sem chamá-la, para ser executada depois.

com_moldura devolve o objeto wrapper (sem parênteses), que é uma closure lembrando de func. Só quando alguém chama o wrapper é que func é executada, entre as mensagens de moldura. Devolver a função em vez de chamá-la é o que torna o decorador reutilizável.

Estudar a aula: O caminho até o decorador

Questão 67 · aula A sintaxe do arroba

A linha @com_moldura acima de def dizer_ola equivale a qual instrução?

  1. dizer_ola = com_moldura (sem parênteses e sem argumento).
  2. dizer_ola = com_moldura(dizer_ola), feita automaticamente após a definição.
  3. com_moldura = dizer_ola, trocando os dois nomes.
  4. Nada; o @ só serve como comentário visual.
Ver a resposta

Resposta: B. dizer_ola = com_moldura(dizer_ola), feita automaticamente após a definição.

O símbolo @ é açúcar sintático: @com_moldura sobre def dizer_ola faz o Python executar dizer_ola = com_moldura(dizer_ola) logo após definir a função. O nome dizer_ola passa a apontar para o wrapper devolvido, sem que você escreva a reatribuição na mão.

Estudar a aula: A sintaxe do arroba

Questão 68 · aula Decorador para qualquer função com args e kwargs

O wrapper chama func(*args, **kwargs) mas não usa return. O que acontece com uma função decorada que deveria retornar um valor?

  1. A função retorna o valor normalmente, o return é opcional.
  2. A função decorada passa a devolver None, mesmo que a original calcule um valor.
  3. O Python levanta um erro avisando que faltou o return.
  4. O valor é impresso na tela automaticamente.
Ver a resposta

Resposta: B. A função decorada passa a devolver None, mesmo que a original calcule um valor.

Sem return, o wrapper executa a função original mas descarta o resultado, então a versão decorada devolve None. É um erro silencioso e traiçoeiro: nada quebra, o valor apenas some. Por isso o wrapper deve terminar com return func(*args, **kwargs).

Estudar a aula: Decorador para qualquer função com args e kwargs

Questão 69 · aula Preservando a identidade com functools.wraps

Para que serve aplicar @functools.wraps(func) sobre o wrapper?

  1. Para o decorador rodar mais rápido.
  2. Para copiar o nome, a docstring e outros metadados da função original para o wrapper.
  3. Para o wrapper aceitar argumentos que antes não aceitava.
  4. Para impedir que a função original seja alterada.
Ver a resposta

Resposta: B. Para copiar o nome, a docstring e outros metadados da função original para o wrapper.

functools.wraps copia para o wrapper os metadados da função original, como __name__ e __doc__. Sem ele, a função decorada se apresentaria como wrapper e perderia a docstring, atrapalhando depuração, help() e documentação. É boa prática usar em todo decorador.

Estudar a aula: Preservando a identidade com functools.wraps

Questão 70 · aula Casos de uso reais de decoradores

Qual é a vantagem de validar argumentos com um decorador em vez de dentro de cada função?

  1. Deixa o programa rodar mais rápido.
  2. Isola a regra de validação em um lugar só e a reaproveita em várias funções, mantendo cada função focada no seu cálculo.
  3. Faz a função aceitar qualquer argumento sem erro.
  4. Elimina a necessidade de usar return no wrapper.
Ver a resposta

Resposta: B. Isola a regra de validação em um lugar só e a reaproveita em várias funções, mantendo cada função focada no seu cálculo.

A validação é um comportamento transversal: repete-se em muitas funções sem ser o objetivo delas. Um decorador escreve essa regra uma vez e a aplica com um @ onde precisar, mantendo cada função limpa e focada. É o caso de uso clássico para decoradores.

Estudar a aula: Casos de uso reais de decoradores

Questão 71 · aula Prática: um decorador de log e tempo

Em @registrar acima de @cronometro sobre uma função, qual decorador envolve a função primeiro?

  1. registrar, porque está escrito mais acima.
  2. cronometro, porque está mais próximo da def; equivale a registrar(cronometro(func)).
  3. Os dois ao mesmo tempo, a ordem não importa.
  4. Nenhum, decoradores empilhados se cancelam.
Ver a resposta

Resposta: B. cronometro, porque está mais próximo da def; equivale a registrar(cronometro(func)).

Decoradores empilhados se aplicam de baixo para cima. O mais próximo da def, cronometro, envolve a função original primeiro; registrar envolve o resultado já cronometrado. Isso equivale a somar_lista = registrar(cronometro(somar_lista)), por isso as mensagens de log ficam por fora das de tempo.

Estudar a aula: Prática: um decorador de log e tempo

Módulo 13: Geradores e iteradores

Questão 72 · aula O que é um iterável

Qual é o papel do StopIteration no protocolo de iteração?

  1. É um erro grave que trava o programa e deve sempre ser evitado.
  2. É o sinal que o iterador levanta para avisar que não há mais itens, e o for para ao recebê-lo.
  3. É o valor especial devolvido pelo primeiro item da sequência.
  4. É a função que cria um iterador a partir de um iterável.
Ver a resposta

Resposta: B. É o sinal que o iterador levanta para avisar que não há mais itens, e o for para ao recebê-lo.

Quando os itens acabam, next() levanta StopIteration. Não é um erro a se temer: é o sinal de fim de linha. O for espera por ele e encerra o laço de forma limpa, sem você precisar contar itens.

Estudar a aula: O que é um iterável

Questão 73 · aula Função geradora com yield

O que acontece quando a execução de uma função geradora chega a um yield?

  1. A função é encerrada de vez, como aconteceria com return.
  2. O valor é entregue a quem percorre e a função pausa ali, continuando depois da linha do yield no próximo pedido.
  3. Todos os valores são calculados e devolvidos juntos em uma lista.
  4. O programa levanta um erro, porque yield só funciona fora de funções.
Ver a resposta

Resposta: B. O valor é entregue a quem percorre e a função pausa ali, continuando depois da linha do yield no próximo pedido.

yield entrega o valor à direita e pausa a função naquele ponto, preservando as variáveis. No próximo next() ou volta do for, ela retoma da linha seguinte ao yield. É o que diferencia yield de return, que encerra a função.

Estudar a aula: Função geradora com yield

Questão 74 · aula Por que usar geradores

Por que um gerador de um milhão de itens ocupa muito menos memória que a lista equivalente?

  1. Porque o gerador comprime os números para ocupar menos espaço.
  2. Porque o gerador não guarda os itens: ele produz cada um sob demanda e só armazena a receita de como gerá-los.
  3. Porque geradores usam disco em vez de memória.
  4. Porque o gerador descarta a metade dos itens automaticamente.
Ver a resposta

Resposta: B. Porque o gerador não guarda os itens: ele produz cada um sob demanda e só armazena a receita de como gerá-los.

A avaliação preguiçosa é a chave: o gerador não materializa a sequência. Ele guarda apenas o estado e a lógica para produzir o próximo item, ocupando um tamanho fixo pequeno, enquanto a lista reserva memória para todos os itens de uma vez.

Estudar a aula: Por que usar geradores

Questão 75 · aula Generator expressions

Qual a diferença entre [x for x in dados] e (x for x in dados)?

  1. Nenhuma, os dois criam exatamente o mesmo objeto.
  2. Os colchetes criam uma lista com todos os itens na memória; os parênteses criam um gerador que produz os itens sob demanda.
  3. Os parênteses criam uma tupla com todos os itens.
  4. Os colchetes são mais lentos, mas ocupam menos memória.
Ver a resposta

Resposta: B. Os colchetes criam uma lista com todos os itens na memória; os parênteses criam um gerador que produz os itens sob demanda.

Colchetes formam uma compreensão de lista, que materializa todos os itens de uma vez. Parênteses formam uma generator expression, que devolve um gerador preguiçoso, produzindo cada item sob demanda e economizando memória.

Estudar a aula: Generator expressions

Questão 76 · aula Encadeando geradores

Em um pipeline de geradores encadeados, como os dados percorrem as etapas?

  1. Cada etapa monta a lista completa e a entrega inteira para a próxima.
  2. Um item por vez atravessa todas as etapas, puxado sob demanda pelo consumo final, sem lista intermediária.
  3. Todas as etapas rodam em paralelo, cada uma em uma cópia dos dados.
  4. O pipeline só funciona se a fonte couber inteira na memória.
Ver a resposta

Resposta: B. Um item por vez atravessa todas as etapas, puxado sob demanda pelo consumo final, sem lista intermediária.

O fluxo é preguiçoso e puxado do fim. Quando o consumo final pede um item, o pedido percorre as etapas de trás para frente e um único item atravessa todo o pipeline antes do próximo começar. Nunca existe uma coleção intermediária completa na memória.

Estudar a aula: Encadeando geradores

Questão 77 · aula Prática: processar um arquivo grande

Por que ler um arquivo grande com for linha in arquivo economiza memória frente a readlines()?

  1. Porque readlines() é mais lento por ser uma função mais antiga.
  2. Porque o for entrega uma linha por vez sob demanda, enquanto readlines() carrega todas as linhas numa lista na memória.
  3. Porque o for comprime o texto do arquivo automaticamente.
  4. Porque readlines() só funciona com arquivos pequenos.
Ver a resposta

Resposta: B. Porque o for entrega uma linha por vez sob demanda, enquanto readlines() carrega todas as linhas numa lista na memória.

O objeto arquivo é iterável e entrega uma linha por vez, lendo do disco sob demanda, como um gerador. Já readlines() traz todas as linhas para uma lista na memória de uma vez. Em arquivos grandes, a leitura preguiçosa usa memória constante, de uma linha por vez.

Estudar a aula: Prática: processar um arquivo grande

Módulo 14: Datas e expressões regulares

Questão 78 · aula Trabalhando com datas

Você tem uma data guardada em uma variável chamada d. Como pega o ano dela?

  1. d.year() com parênteses, porque é um método.
  2. d.year, sem parênteses, porque year é um atributo do objeto de data.
  3. int(d[6:10]), fatiando a data como se fosse texto.
  4. d.get_year(), o método padrão para ler o ano.
Ver a resposta

Resposta: B. d.year, sem parênteses, porque year é um atributo do objeto de data.

Um objeto date ou datetime guarda o ano no atributo .year, lido sem parênteses. Parênteses são para métodos, como .today(). Fatiar como texto (d[6:10]) só funciona em strings e é justamente o que o tipo de data evita.

Estudar a aula: Trabalhando com datas

Questão 79 · aula Formatando e lendo datas

O usuário digitou "15/08/2026". Qual chamada transforma esse texto em um objeto de data?

  1. datetime.strftime("15/08/2026", "%d/%m/%Y")
  2. datetime.strptime("15/08/2026", "%d/%m/%Y")
  3. date("15/08/2026")
  4. datetime.strptime("15/08/2026", "%Y-%m-%d")
Ver a resposta

Resposta: B. datetime.strptime("15/08/2026", "%d/%m/%Y")

Para ler texto e virar objeto, use strptime, com o molde que descreve o texto. Como está no formato dd/mm/aaaa, o molde é "%d/%m/%Y". strftime faz o contrário (objeto para texto) e o molde "%Y-%m-%d" não bate com as barras do texto.

Estudar a aula: Formatando e lendo datas

Questão 80 · aula Cálculos com datas

Você subtraiu duas datas e guardou em dif. Como pega o número inteiro de dias entre elas?

  1. dif, porque a subtração de datas já devolve um número.
  2. dif.days, porque a subtração devolve um timedelta e .days extrai os dias.
  3. int(dif), convertendo o timedelta direto para inteiro.
  4. dif.total(), o método que soma os dias.
Ver a resposta

Resposta: B. dif.days, porque a subtração devolve um timedelta e .days extrai os dias.

Subtrair duas datas devolve um timedelta, não um número. Para ler o total de dias como inteiro, use o atributo .days. Converter o timedelta com int() dá erro, e a subtração sozinha ainda é uma duração, não um número.

Estudar a aula: Cálculos com datas

Questão 81 · aula O que é uma expressão regular

Por que se escreve o padrão como raw string, com r antes das aspas, por exemplo r"\d+"?

  1. Porque o módulo re só aceita raw strings e recusa strings normais.
  2. Porque a barra invertida das regex conflita com os escapes das strings normais, e a raw string a trata de forma literal.
  3. Porque a raw string faz a busca ficar mais rápida.
  4. Porque sem o r o Python transforma o padrão em número.
Ver a resposta

Resposta: B. Porque a barra invertida das regex conflita com os escapes das strings normais, e a raw string a trata de forma literal.

Regex usa muito a barra invertida (como em \d), que também é especial nas strings comuns do Python. A raw string (r"...") trata a barra de forma literal, então o padrão fica igual ao dos manuais. Funciona sem o r dobrando as barras, mas é mais confuso.

Estudar a aula: O que é uma expressão regular

Questão 82 · aula Padrões básicos de regex

Qual padrão confere se um texto é formado apenas por dígitos, do começo ao fim?

  1. r"\d", que casa com um dígito em qualquer posição.
  2. r"^\d+$", que exige um ou mais dígitos do início (^) ao fim ($).
  3. r"\d*", que aceita zero ou mais dígitos em qualquer lugar.
  4. r"[0-9]", que casa com um único dígito no meio do texto.
Ver a resposta

Resposta: B. r"^\d+$", que exige um ou mais dígitos do início (^) ao fim ($).

As âncoras ^ e $ prendem o padrão ao começo e ao fim, e \d+ exige um ou mais dígitos. Sem as âncoras, o padrão casaria com dígitos em qualquer parte, aceitando textos como 12a34. re.fullmatch(r"\d+", texto) faria o mesmo papel.

Estudar a aula: Padrões básicos de regex

Questão 83 · aula Prática: validar e extrair

Você usou re.findall(r"\d{2}/\d{2}/\d{4}", texto) e obteve uma lista de textos. Como transformar cada um em objeto de data?

  1. date(texto), passando a string direto para o construtor date.
  2. datetime.strptime(d, "%d/%m/%Y") para cada d, que lê o texto e devolve o objeto.
  3. int(d), convertendo a data em número.
  4. d.strftime("%d/%m/%Y"), que formata a string.
Ver a resposta

Resposta: B. datetime.strptime(d, "%d/%m/%Y") para cada d, que lê o texto e devolve o objeto.

findall devolve textos; para virar objeto de data usa-se strptime com o molde "%d/%m/%Y". date() não aceita string, int() não faz sentido para uma data e strftime é o caminho contrário (objeto para texto), além de não funcionar sobre uma string.

Estudar a aula: Prática: validar e extrair

Módulo 15: Testes automatizados

Questão 84 · aula Por que testar o código

Qual é o maior benefício de ter testes automatizados?

  1. Deixar o programa rodar mais rápido para o usuário final.
  2. A confiança para mudar e melhorar o código sabendo que uma regressão será avisada.
  3. Substituir totalmente a necessidade de entender o código.
  4. Escrever menos código no total do projeto.
Ver a resposta

Resposta: B. A confiança para mudar e melhorar o código sabendo que uma regressão será avisada.

Testes até ajudam a achar erros, mas o ganho central é a confiança para mexer no código. Ao rodar os testes depois de uma mudança, você é avisado na hora se quebrou algo que já funcionava, o que torna refatorar e ampliar seguro.

Estudar a aula: Por que testar o código

Questão 85 · aula Por que testar o código

Por que testar manualmente vira um problema em um programa que cresce?

  1. Porque o Python proíbe conferir resultados na tela.
  2. Porque cada mudança exige refazer toda a conferência na mão, e por preguiça você acaba pulando casos.
  3. Porque testar na mão apaga o código antigo.
  4. Porque a conferência manual sempre dá o resultado errado.
Ver a resposta

Resposta: B. Porque cada mudança exige refazer toda a conferência na mão, e por preguiça você acaba pulando casos.

O custo do teste manual está na repetição: a cada alteração é preciso reconferir tudo de novo. Como isso é trabalhoso, o programador acaba testando só o que mexeu, e regressões em outras partes passam despercebidas.

Estudar a aula: Por que testar o código

Questão 86 · aula O comando assert

O que acontece quando a condição de um assert é falsa?

  1. O programa ignora a linha e continua normalmente.
  2. O Python levanta um AssertionError, interrompendo a execução, com a mensagem opcional se houver.
  3. O assert corrige o valor errado automaticamente.
  4. O programa reinicia do começo.
Ver a resposta

Resposta: B. O Python levanta um AssertionError, interrompendo a execução, com a mensagem opcional se houver.

Quando a condição é verdadeira, o assert passa em silêncio. Quando é falsa, o Python levanta um AssertionError e interrompe a execução, mostrando junto a mensagem escrita depois da vírgula, quando ela existe.

Estudar a aula: O comando assert

Questão 87 · aula Testes com unittest

Em uma classe unittest.TestCase, como você verifica se dois valores são iguais?

  1. Com um assert cru dentro do método test_.
  2. Com self.assertEqual(obtido, esperado), que compara e, ao falhar, mostra os dois valores.
  3. Com print(obtido == esperado) e conferindo na tela.
  4. Com return obtido == esperado no método de teste.
Ver a resposta

Resposta: B. Com self.assertEqual(obtido, esperado), que compara e, ao falhar, mostra os dois valores.

Dentro de um TestCase, o método self.assertEqual(obtido, esperado) faz a comparação de igualdade e, quando falha, mostra automaticamente o valor obtido e o esperado no relatório, sem você precisar montar a mensagem à mão.

Estudar a aula: Testes com unittest

Questão 88 · aula Conhecendo o pytest

Qual afirmação sobre o pytest está correta?

  1. Ele já vem instalado com o Python, como o unittest.
  2. É um pacote externo, instalado com pip, e permite escrever testes como funções com assert direto.
  3. Ele exige que todo teste esteja dentro de uma classe TestCase.
  4. Ele só roda testes que usam self.assertEqual.
Ver a resposta

Resposta: B. É um pacote externo, instalado com pip, e permite escrever testes como funções com assert direto.

O pytest não faz parte da biblioteca padrão: é instalado com pip install pytest. Seu diferencial é a simplicidade, pois cada teste é uma função test_ que usa o assert nativo, sem classe nem métodos especiais, e ele ainda roda testes escritos em unittest.

Estudar a aula: Conhecendo o pytest

Questão 89 · aula Testando casos de borda

Por que vale escrever um teste separado para cada comportamento, em vez de um teste grande?

  1. Porque o unittest não aceita mais de um assert por método.
  2. Porque, com um comportamento por teste, uma falha aponta exatamente o que quebrou e o nome do teste explica a história.
  3. Porque testes pequenos rodam muito mais rápido que os grandes.
  4. Porque o Python conta apenas o primeiro assert de cada método.
Ver a resposta

Resposta: B. Porque, com um comportamento por teste, uma falha aponta exatamente o que quebrou e o nome do teste explica a história.

Com um comportamento por teste e um nome descritivo, uma falha localiza o problema com precisão e o próprio nome do método conta o que deveria acontecer. Um teste que mistura vários casos só avisa que algo no bolo quebrou, sem dizer o quê.

Estudar a aula: Testando casos de borda

Questão 90 · aula Prática: testar uma função

Na prática, por que a distância zero e a distância negativa foram testadas além do caso de 10 km?

  1. Porque o Python exige testar pelo menos três valores por função.
  2. Porque zero é uma borda (só a bandeirada) e negativo é entrada inválida (deve levantar ValueError), e é aí que os bugs aparecem.
  3. Porque números pequenos deixam os testes mais rápidos.
  4. Porque sem eles a função não roda.
Ver a resposta

Resposta: B. Porque zero é uma borda (só a bandeirada) e negativo é entrada inválida (deve levantar ValueError), e é aí que os bugs aparecem.

O caso de 10 km é o caminho feliz. Zero é uma borda importante, onde o preço deve ser só a bandeirada, e a distância negativa é uma entrada inválida que a função deve rejeitar com ValueError. Cobrir borda e entrada inválida é onde os testes mais pegam bugs.

Estudar a aula: Prática: testar uma função

Módulo 16: Projeto final: agenda de contatos

Questão 91 · aula A visão do projeto

Por que o projeto será construído de forma incremental, aula por aula?

  1. Porque o Python exige que programas grandes sejam divididos em arquivos.
  2. Para manter o programa sempre funcionando e saber onde procurar quando algo quebrar.
  3. Porque classes só podem ser escritas uma de cada vez.
  4. Para o programa rodar mais rápido no final.
Ver a resposta

Resposta: B. Para manter o programa sempre funcionando e saber onde procurar quando algo quebrar.

Construir de forma incremental mantém o programa rodando a cada passo. Como só uma coisa muda por vez, quando um erro aparece você sabe exatamente onde ele foi introduzido. É mais seguro do que escrever tudo e testar só no fim.

Estudar a aula: A visão do projeto

Questão 92 · aula Modelando a agenda com classes

Qual é o papel do método __str__ na classe Contato?

  1. Criar o contato e guardar os atributos.
  2. Definir o texto legível que aparece quando o contato é impresso com print.
  3. Salvar o contato em um arquivo.
  4. Comparar dois contatos para saber se são iguais.
Ver a resposta

Resposta: B. Definir o texto legível que aparece quando o contato é impresso com print.

__str__ devolve a representação em texto do objeto. Com ele, print(contato) mostra uma linha legível como Ana | 11999998888 | ... em vez do endereço técnico do objeto na memória. Quem cria o objeto é o __init__.

Estudar a aula: Modelando a agenda com classes

Questão 93 · aula Os métodos da agenda

Por que buscar_por_nome compara nome.lower() com c.nome.lower()?

  1. Para deixar a busca mais rápida.
  2. Para ignorar maiúsculas e minúsculas, fazendo 'ana' encontrar 'Ana Souza'.
  3. Porque compreensões só funcionam com texto em minúsculo.
  4. Para remover os espaços do nome.
Ver a resposta

Resposta: B. Para ignorar maiúsculas e minúsculas, fazendo 'ana' encontrar 'Ana Souza'.

Comparar tudo em minúsculo com lower torna a busca insensível a maiúsculas: 'ana', 'Ana' e 'ANA' encontram o mesmo contato. Sem isso, o usuário precisaria digitar o nome com a grafia exata, o que seria frustrante.

Estudar a aula: Os métodos da agenda

Questão 94 · aula Tratando erros com uma exceção própria

Por que o tratamento com try e except fica no menu, e não dentro de buscar_por_nome?

  1. Porque métodos de classe não podem usar try e except.
  2. Porque só o menu tem contexto para responder ao usuário; a agenda apenas sinaliza o erro.
  3. Porque a exceção some se for tratada dentro do método.
  4. Porque o try é mais rápido fora da classe.
Ver a resposta

Resposta: B. Porque só o menu tem contexto para responder ao usuário; a agenda apenas sinaliza o erro.

O método levanta a exceção onde o problema é descoberto, mas quem sabe como responder ao usuário é o menu. Tratar no menu mantém a agenda reaproveitável: ela sinaliza o erro e deixa cada interface decidir como reagir.

Estudar a aula: Tratando erros com uma exceção própria

Questão 95 · aula Salvando a agenda em JSON

Por que a agenda precisa de para_dicionario e de_dicionario para usar JSON?

  1. Porque o JSON é mais rápido com dicionários.
  2. Porque o JSON guarda tipos básicos como dicionários, não objetos Contato, então é preciso traduzir nos dois sentidos.
  3. Porque classmethods exigem dicionários.
  4. Porque sem eles o arquivo ficaria com acentos errados.
Ver a resposta

Resposta: B. Porque o JSON guarda tipos básicos como dicionários, não objetos Contato, então é preciso traduzir nos dois sentidos.

O JSON entende textos, números, listas e dicionários, mas não a classe Contato. para_dicionario traduz o objeto para salvar e de_dicionario reconstrói o objeto ao carregar. Sem essas pontes, o json.dump não saberia como gravar um Contato.

Estudar a aula: Salvando a agenda em JSON

Questão 96 · aula Exportar para CSV e o menu

Por que o programa salva o JSON logo após adicionar ou remover um contato?

  1. Para o programa rodar mais rápido.
  2. Para garantir que a mudança persista mesmo que o usuário feche o programa em seguida.
  3. Porque o menu não funciona sem salvar.
  4. Porque o CSV exige que o JSON esteja atualizado.
Ver a resposta

Resposta: B. Para garantir que a mudança persista mesmo que o usuário feche o programa em seguida.

Salvar logo após cada mudança garante que nada se perca se o programa for fechado. Assim a próxima execução carrega o estado mais recente. É a diferença entre uma agenda que lembra e uma que esquece ao sair.

Estudar a aula: Exportar para CSV e o menu

Questão 97 · aula Testando a agenda e próximos passos

Por que o teste usa assertRaises ao buscar um contato inexistente?

  1. Para ignorar o erro e continuar o teste.
  2. Para afirmar que aquela chamada deve levantar ContatoNaoEncontradoError, testando o caminho de erro.
  3. Para tornar o teste mais rápido.
  4. Porque buscar_por_nome não funciona sem assertRaises.
Ver a resposta

Resposta: B. Para afirmar que aquela chamada deve levantar ContatoNaoEncontradoError, testando o caminho de erro.

assertRaises verifica que o bloco levanta a exceção esperada. Se buscar_por_nome não levantasse ContatoNaoEncontradoError, o teste falharia. Testar o caminho de erro garante que o tratamento continua funcionando quando você mexe no código.

Estudar a aula: Testando a agenda e próximos passos

Terminou a lista?

Quem acertou quase tudo já pode encarar o exame final do curso, com 20 questões sorteadas e aprovação a partir de 70%. Quem errou bastante ganha mais voltando às aulas dos módulos em que tropeçou: cada questão acima leva direto à aula certa.

Ir para o Curso de Python Intermediário