Guia de estudo

Correção da 2ª VA — Gabarito comentado (Aulas 14–24)
CORREÇÃO · 2ª VA

Correção da 2ª VA

Gabarito comentado — teórica e prática

Questão por questão: o código, a saída real e por que a resposta certa é certa. Aulas 14–24.

10 teóricas 2 práticas Gabarito Saída comentada
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 1 · Tratamento de exceções

finally roda sempre; o else é pulado quando há exceção

O que este programa imprime?

questao01.py
def processar(a, b):
    try:
        print(a / b)
    except ZeroDivisionError:
        print("divisão por zero")
    else:
        print("deu certo")
    finally:
        print("fim")

processar(10, 0)
# Saída no terminal:
# divisão por zero
# fim
Gabarito: E. 10 / 0 levanta ZeroDivisionError, capturada pelo except → "divisão por zero". Como HOUVE exceção, o else (caminho feliz) é pulado. O finally roda SEMPRE → "fim".
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 2 · Encapsulamento

o setter valida na atribuição direta e na criação

O que acontece ao rodar este programa?

questao02.py
class Produto:
    def __init__(self, nome, preco):
        self.nome = nome
        self.preco = preco

    @property
    def preco(self):
        return self._preco

    @preco.setter
    def preco(self, valor):
        if valor < 0:
            raise ValueError("Preço não pode ser negativo")
        self._preco = valor

p = Produto("Ração", 50.0)
p.preco = 45.0
print(p.preco)       # 45.0
p.preco = -10        # ValueError: Preço não pode ser negativo
Gabarito: C. O setter roda TANTO no __init__ quanto na atribuição direta. 50 e 45 passam; print mostra 45.0. Ao atribuir -10, o if valor < 0 levanta ValueError e o programa para. (Migrada do simulado Q1 — lá a correta era A.)
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 3 · Herança + __str__

__str__ não sobrescrito é herdado da classe-mãe

O que este programa imprime, nesta ordem?

questao03.py
class Veiculo:
    def __init__(self, marca):
        self.marca = marca

    def descrever(self):
        return f"Veículo {self.marca}"

    def __str__(self):
        return f"Veiculo({self.marca})"

class Carro(Veiculo):
    def __init__(self, marca, portas):
        super().__init__(marca)
        self.portas = portas

    def descrever(self):
        return f"{super().descrever()} com {self.portas} portas"

c = Carro("Fiat", 4)
print(c.descrever())   # Veículo Fiat com 4 portas
print(c)               # Veiculo(Fiat)
Gabarito: A. Carro sobrescreve descrever() e usa super().descrever() pra reaproveitar a mãe e ACRESCENTAR as portas. Já __str__ NÃO foi sobrescrito em Carroprint(c) usa o herdado de VeiculoVeiculo(Fiat).
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 4 · Exceção customizada

a exceção guarda o dado, lido no except

O que este programa imprime?

questao04.py
class EstoqueInsuficienteError(Exception):
    def __init__(self, pedido, disponivel):
        self.faltam = pedido - disponivel
        super().__init__(f"Faltam {self.faltam} unidades")

class Estoque:
    def __init__(self, disponivel):
        self.disponivel = disponivel

    def retirar(self, pedido):
        if pedido > self.disponivel:
            raise EstoqueInsuficienteError(pedido, self.disponivel)
        self.disponivel -= pedido

estoque = Estoque(5)
try:
    estoque.retirar(8)
except EstoqueInsuficienteError as erro:
    print("Erro:", erro)        # Erro: Faltam 3 unidades
    print("Faltam:", erro.faltam)  # Faltam: 3
Gabarito: D. retirar() levanta a exceção quando o pedido passa do disponível. O super().__init__(mensagem) faz print(erro) mostrar "Faltam 3 unidades". O atributo self.faltam (8 − 5 = 3) é lido no except via erro.faltam.
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 5 · ABC + polimorfismo

cada subclasse responde o mesmo método do seu jeito

O que este programa imprime?

questao05.py
from abc import ABC, abstractmethod

class Animal(ABC):
    def __init__(self, nome):
        self.nome = nome

    @abstractmethod
    def falar(self):
        pass

class Cachorro(Animal):
    def falar(self):
        return "Au au"

class Gato(Animal):
    def falar(self):
        return "Miau"

animais = [Cachorro("Rex"), Gato("Mimi")]
for a in animais:
    print(f"{a.nome}: {a.falar()}")
# Saída no terminal:
# Rex: Au au
# Mimi: Miau
Gabarito: D. Polimorfismo: o mesmo for chama a.falar() em classes DIFERENTES e cada uma responde do seu jeito. Animal é ABC (não instanciável direto), mas Cachorro/Gato implementam falar(), então instanciam normal. (Migrada do simulado Q3 — lá era A.)
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 6 · Coleções (sorted + key)

sorted(key=...) devolve uma lista nova ordenada

O que é impresso?

questao06.py
produtos = [("cafe", 18), ("leite", 5), ("pao", 8)]
ordenados = sorted(produtos, key=lambda p: p[1])
print(ordenados)
# [('leite', 5), ('pao', 8), ('cafe', 18)]
Gabarito: C. sorted(key=lambda p: p[1]) ordena pelo 2º elemento (o preço), crescente → leite(5), pao(8), cafe(18). sorted() devolve uma lista NOVA (não None — isso seria .sort()). O key=lambda é a mesma ideia do Strategy (aula 21).
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 7 · Persistência (from_row/to_params)

from_row remonta o objeto com o id gerado pelo banco

Rodando num banco loja.db recém-criado, o que este programa imprime?

questao07.py
import sqlite3

class Produto:
    def __init__(self, nome, preco, id=None):
        self.id = id
        self.nome = nome
        self.preco = preco

    @classmethod
    def from_row(cls, linha):
        id, nome, preco = linha
        return cls(nome, preco, id)

    def to_params(self):
        return (self.nome, self.preco)

    def __str__(self):
        return f"#{self.id} {self.nome} — R$ {self.preco:.2f}"

con = sqlite3.connect("loja.db")
con.execute("CREATE TABLE produtos (id INTEGER PRIMARY KEY AUTOINCREMENT, nome TEXT, preco REAL)")

cafe = Produto("Café", 18.0)
con.execute("INSERT INTO produtos (nome, preco) VALUES (?, ?)", cafe.to_params())

linha = con.execute("SELECT id, nome, preco FROM produtos").fetchone()
p = Produto.from_row(linha)
print(p)             # #1 Café — R$ 18.00
Gabarito: B. to_params() devolve (nome, preco) SEM o id (o banco gera via AUTOINCREMENT). O SELECT devolve (1, 'Café', 18.0); from_row remonta o objeto JÁ com id=1#1. O :.2f18.00. (Migrada do simulado Q20 — lá era E.)
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 8 · Strategy

o Contexto delega a UMA estratégia intercambiável

O que este programa imprime?

questao08.py
class Carrinho:
    def __init__(self, desconto):
        self.desconto = desconto
        self.itens = []

    def adicionar(self, preco):
        self.itens.append(preco)

    def total(self):
        subtotal = sum(self.itens)
        return self.desconto(subtotal)

def sem_desconto(v):
    return v

def black_friday(v):
    return v * 0.5

c = Carrinho(black_friday)
c.adicionar(100)
c.adicionar(60)
print(c.total())     # 80.0
Gabarito: B. Strategy: o Carrinho (Contexto) guarda UMA estratégia (a função black_friday) e delega o cálculo a ela. total() soma os itens (160) e aplica → 160 * 0.5 = 80.0. Trocar a estratégia muda o resultado sem mexer no Carrinho.
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 9 · Tkinter — App(tk.Tk) + Listbox

o Listbox espelha a lista após o refresh

O que este programa imprime?

questao09.py
import tkinter as tk

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.clientes = ["Ana", "Beto", "Carla"]
        self.lista = tk.Listbox(self)
        self.lista.pack()
        self.atualizar()

    def atualizar(self):
        self.lista.delete(0, tk.END)
        for c in self.clientes:
            self.lista.insert(tk.END, c)

    def remover(self, nome):
        self.clientes.remove(nome)
        self.atualizar()

app = App()
app.remover("Beto")
print(app.lista.get(1))   # Carla
Gabarito: A. atualizar() LIMPA o Listbox (delete(0, tk.END)) e re-insere de self.clientes → o Listbox espelha a lista. Antes, a posição 1 era "Beto"; depois de remover("Beto"), a lista vira ['Ana', 'Carla'] e get(1) devolve "Carla". (Migrada do simulado Q17 — lá era D.)
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 10 · SQLite (NOT NULL)

inserir None numa coluna NOT NULL levanta IntegrityError

Rodando num banco loja.db recém-criado, o que este programa imprime?

questao10.py
import sqlite3

con = sqlite3.connect("loja.db")
con.execute("CREATE TABLE itens (id INTEGER PRIMARY KEY, nome TEXT NOT NULL)")
try:
    con.execute("INSERT INTO itens (nome) VALUES (?)", (None,))
    print("inserido")
except sqlite3.IntegrityError:
    print("recusado pelo NOT NULL")   # recusado pelo NOT NULL
Gabarito: E. A coluna nome é NOT NULL, então inserir None fere a regra e o banco levanta sqlite3.IntegrityError — capturada pelo except → "recusado pelo NOT NULL". É esse o mecanismo que uma exceção de domínio traduz num Repositório.
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 1 · Cardápio (POO)

ABC + herança + polimorfismo + property

Implementar ItemCardapio (ABC, property com ValueError) + subclasses Pizza e Bebida; polimorfismo no loop.

questao1.py
from abc import ABC, abstractmethod

class ItemCardapio(ABC):
    def __init__(self, nome, preco):
        self.nome = nome
        self.preco = preco            # passa pelo setter

    @property
    def preco(self):
        return self._preco

    @preco.setter
    def preco(self, valor):
        if valor <= 0:
            raise ValueError("preço deve ser positivo")
        self._preco = valor

    @abstractmethod
    def descricao(self):
        pass

class Pizza(ItemCardapio):
    def __init__(self, nome, preco, tamanho):
        super().__init__(nome, preco)
        self.tamanho = tamanho

    def descricao(self):
        return f"Pizza {self.nome} ({self.tamanho}) — R$ {self.preco:.2f}"

class Bebida(ItemCardapio):
    def descricao(self):
        return f"Bebida {self.nome} — R$ {self.preco:.2f}"

# Teste + saída:
itens = [Pizza("Calabresa", 45.0, "grande"), Bebida("Guaraná", 8.0)]
for item in itens:
    print(item.descricao())
try:
    Pizza("Promo", 0, "broto")
except ValueError as erro:
    print("Recusada:", erro)
# Pizza Calabresa (grande) — R$ 45.00
# Bebida Guaraná — R$ 8.00
# Recusada: preço deve ser positivo
Avaliar: ABC com @abstractmethod; herança com super().__init__ (e Bebida reaproveitando o construtor); polimorfismo no loop; property/setter com ValueError. O texto da mensagem pode variar — conta o comportamento.
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Questão 2 · App Tkinter + SQLite

App(tk.Tk) que persiste no banco com from_row/to_params

Implementar Pizza (from_row/to_params/__str__) + RepositorioPizza (CRUD SQLite) + App(tk.Tk) que cadastra e lista.

questao2.py
import tkinter as tk
import sqlite3
from pathlib import Path

BANCO = Path(__file__).parent / "pizzaria.db"

class Pizza:
    def __init__(self, nome, preco, id=None):
        self.id = id
        self.nome = nome
        self.preco = preco

    @classmethod
    def from_row(cls, linha):
        id, nome, preco = linha
        return cls(nome, preco, id)

    def to_params(self):
        return (self.nome, self.preco)

    def __str__(self):
        return f"{self.nome} — R$ {self.preco:.2f}"

class RepositorioPizza:
    def __init__(self, caminho=BANCO):
        self.caminho = caminho
        with sqlite3.connect(self.caminho) as con:
            con.execute(
                "CREATE TABLE IF NOT EXISTS pizzas ("
                "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                "nome TEXT NOT NULL, "
                "preco REAL NOT NULL)"
            )

    def salvar(self, pizza):
        with sqlite3.connect(self.caminho) as con:
            cursor = con.execute(
                "INSERT INTO pizzas (nome, preco) VALUES (?, ?)",
                pizza.to_params(),
            )
            pizza.id = cursor.lastrowid

    def listar(self):
        with sqlite3.connect(self.caminho) as con:
            cursor = con.execute("SELECT id, nome, preco FROM pizzas ORDER BY id")
            return [Pizza.from_row(l) for l in cursor.fetchall()]

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Pizzaria")
        self.repo = RepositorioPizza()
        self.entrada_nome = tk.Entry(self)
        self.entrada_nome.pack()
        self.entrada_preco = tk.Entry(self)
        self.entrada_preco.pack()
        tk.Button(self, text="Adicionar", command=self.adicionar).pack()
        self.lista = tk.Listbox(self, width=40)
        self.lista.pack()
        self.atualizar()

    def adicionar(self):
        nome = self.entrada_nome.get()
        preco = float(self.entrada_preco.get())
        self.repo.salvar(Pizza(nome, preco))
        self.atualizar()
        print(f"Salva: {nome}")

    def atualizar(self):
        self.lista.delete(0, tk.END)
        for p in self.repo.listar():
            self.lista.insert(tk.END, str(p))

# No app real: App().mainloop(). Teste (simula o clique):
app = App()
app.entrada_nome.insert(0, "Calabresa")
app.entrada_preco.insert(0, "45")
app.adicionar()
print("No cardápio:", app.lista.get(0))
# Salva: Calabresa
# No cardápio: Calabresa — R$ 45.00
Avaliar: App(tk.Tk) com super().__init__(); Entry.get() no callback; command= como valor; refresh do Listbox (delete(0, tk.END) + reinsere); from_row/to_params e o CRUD com ?; o id vindo do banco via lastrowid.
Correção da 2ª VA — Gabarito comentado (Aulas 14–24)

Resumo

Gabarito completo — parte teórica

As dez respostas em um lugar. A parte prática é avaliada pela execução correta, não por letra.

Q1

E

exceções

Q2

C

encapsulamento

Q3

A

herança

Q4

D

exceção custom

Q5

D

ABC/polim.

Q6

C

sorted+key

Q7

B

from_row

Q8

B

Strategy

Q9

A

App/Listbox

Q10

E

NOT NULL