Guia de estudo

Revisão para a 2ª VA — Aulas 14 a 24
REVISÃO · 4h

Revisão para a 2ª VA

Aulas 14 a 24 — prova cumulativa, ênfase no conteúdo novo

A 2ª VA cobre tudo, mas o foco é o que veio depois da 1ª VA: exceções, arquivos, coleções, padrões de projeto, Tkinter e SQLite. A base de POO (01–12) sustenta tudo por baixo.

Exceções Arquivos Coleções Singleton/Factory Observer/Strategy Tkinter SQLite
Revisão para a 2ª VA — Aulas 14 a 24

O caminho de hoje

O mapa da 2ª VA

Sete blocos novos, agrupados por família. Cada bloco com a ideia, o código mínimo e a armadilha clássica.

14

Tratamento de Exceções

raise, try/except/else/finally, hierarquia e exceções customizadas.

17

Manipulação de Arquivos

open, with, encoding utf-8, modos r/w/a, pathlib e JSON.

18

Coleções e POO

list/tuple/dict/set, comprehension, sorted(key=) e sets de objetos.

20

Singleton & Factory

Padrões criacionais: uma instância só; quem decide qual classe criar.

21

Observer & Strategy

Padrões comportamentais: avisar muitos × delegar a um algoritmo trocável.

22–23

Tkinter

Janela, widgets, command= (Observer), Listbox, messagebox e App(tk.Tk).

24

SQLite

Banco relacional, CRUD com placeholder ?, ORM manual e Repositório.

Azul = dados e erros · amarelo = padrões GoF · vermelho = interface e persistência. Por baixo de tudo, a base de POO das aulas 01–12.
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 14 · Exceções

O quarteto try / except / else / finally

  • 🚨 Separe quem detecta de quem trata: a função usa raise para sinalizar; quem chamou decide a reação com try/except.
  • 🧯 Analogia do disjuntor: o raise desarma na origem; o try/except é você no quadro de luz decidindo o que fazer.
  • 🕳️ Devolver None ou imprimir aviso mascara o erro: ele estoura longe da causa, três telas depois, num AttributeError.

try

Marca o bloco arriscado que pode levantar uma exceção.

except

Captura a exceção levantada e executa o plano B. Mire um tipo específico.

else

Roda só se o try terminou sem exceção — o caminho feliz.

finally

Roda SEMPRE, com erro ou sem. Ideal para limpeza (fechar recurso).

Revisão para a 2ª VA — Aulas 14 a 24

Bloco 14 · Exceções

Hierarquia + exceção customizada com dados

Exceções são classes com herança: capturar a mãe (LookupError) pega as filhas (IndexError, KeyError). E uma exceção sua pode carregar dados do erro.

excecoes.py
# hierarquia: IndexError é filha de LookupError (aula 14)
try:
    lista = [1, 2, 3]
    print(lista[10])
except LookupError as erro:          # LookupError pega IndexError e KeyError
    print(f"Capturado por LookupError: {type(erro).__name__}")
# Capturado por LookupError: IndexError

# exceção customizada carrega dados do erro (aula 14)
class SaldoInsuficienteError(Exception):
    def __init__(self, saldo, valor):
        self.falta = valor - saldo
        super().__init__(f"Faltam R$ {self.falta:.2f}")   # texto vai pro print(erro)

try:
    raise SaldoInsuficienteError(saldo=100, valor=150)
except SaldoInsuficienteError as erro:
    print(erro)              # Faltam R$ 50.00
    print(erro.falta)        # 50
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 14 · Exceções

Vocabulário e armadilhas de exceções

item detalhe
raise Levanta uma exceção de propósito. Interrompe a função e sobe o erro para quem chamou.
as erro Guarda o objeto capturado. print(erro) mostra a mensagem; erro.falta lê dados customizados.
Exceção customizada Classe que herda de Exception. O nome (SaldoInsuficienteError) já documenta o erro do domínio.
Ordem dos except Específicos primeiro, genéricos por último — senão a classe-mãe captura antes da filha.
except: pass Anti-padrão (engolir o erro). Some da tela, mas o bug continua vivo. Nunca use.
Nunca capture BaseException Inclui KeyboardInterrupt e SystemExit. Capture Exception ou algo mais específico.
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 17 · Arquivos

with open — o ritual abrir → usar → fechar

O with fecha o arquivo sozinho (é o finally da aula 14 automático). encoding="utf-8" é obrigatório para o português; "w" apaga tudo. Quatro formas de ler: read() (tudo), readline() (uma linha, com o \n), readlines() (lista) e o pythônico for linha in f.

arquivos.py
# with abre e fecha sozinho (aula 17) — é o finally da aula 14 automático
with open("pedidos.txt", "w", encoding="utf-8") as f:   # "w" cria e APAGA tudo
    f.write("Ana;Calabresa;39.90\n")                     # write não pula linha sozinho

with open("pedidos.txt", "a", encoding="utf-8") as f:   # "a" anexa e preserva
    f.write("Bruno;Portuguesa;42.00\n")

# as 4 formas de LER (aula 17) — read() traz o arquivo TODO numa string só:
with open("pedidos.txt", "r", encoding="utf-8") as f:
    print(repr(f.readline()))     # 'Ana;Calabresa;39.90\n'  (UMA linha, COM o \n)

with open("pedidos.txt", "r", encoding="utf-8") as f:
    print(f.readlines())          # ['Ana;Calabresa;39.90\n', 'Bruno;Portuguesa;42.00\n']  (lista com todas)

with open("pedidos.txt", "r", encoding="utf-8") as f:   # "r" lê (padrão) — a forma pythônica:
    for linha in f:
        print(linha.strip())      # .strip() tira o \n
# Ana;Calabresa;39.90
# Bruno;Portuguesa;42.00
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 17 · Arquivos

Texto com separador × JSON

As duas formas persistem objetos em disco. A diferença é robustez: o que acontece quando o dado tem um caractere especial.

Texto com ;

  • 📄 Grava Ana;Calabresa;39.90 e lê com linha.split(";").
  • 📄 Simples, mas quebra se o dado tiver um ; no meio.
  • 📄 Ao carregar, TUDO é string: valor vem "39.90", precisa de float(valor).
  • 📄 Bom para dados simples e planos.

JSON

  • 🧱 json.dump(obj.to_dict(), f, ensure_ascii=False, indent=2) grava estruturado.
  • 🧱 json.load(f) reconstrói o dicionário — tipos preservados (número volta número).
  • 🧱 Aguenta vírgula, ponto-e-vírgula e acento no conteúdo sem quebrar.
  • 🧱 json.dump grava dicionários, não objetos: converta com to_dict() antes.
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 17 · Arquivos

pathlib e objetos que se salvam

  • 🗺️ from pathlib import Path: Path("dados") / "pedidos.txt" monta o caminho; Path(__file__).parent ancora o arquivo ao lado do script.
  • 💾 Persistir objeto: converter em texto ao salvar e reconstruir pelo construtor ao carregar. salvar() é de instância; from_dict() costuma ser @classmethod (factory da aula 03).
  • ⚠️ "Rodei e não achei o arquivo": quase sempre é caminho relativo — salvou na pasta de execução, não onde está o .py.

to_dict(self)

Método de instância: objeto → dicionário, pronto para json.dump.

from_dict(cls, dados)

@classmethod: dicionário → objeto novo, via construtor.

FileNotFoundError

Modo "r" em arquivo que não existe. Trate com try/except (aula 14).

Revisão para a 2ª VA — Aulas 14 a 24

Bloco 18 · Coleções

As 4 coleções — quando usar cada uma

item detalhe
list [ ] Ordenada, mutável, aceita repetidos, tem índice. A coleção do dia a dia.
tuple ( ) Ordenada mas imutável. Para dados fixos: coordenadas, RGB, um registro que não muda.
dict { chave: valor } Mapeia chave → valor. Acesso direto pela chave — o repositório por código.
set set( ) Sem ordem e sem repetição. Elimina duplicatas. Atenção: { } vazio é DICIONÁRIO, use set().
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 18 · Coleções

List comprehension: transformar e filtrar

[ expressão for item in coleção if condição ]. A expressão decide o que entra; o if (opcional) filtra. Leia como frase: "o nome, pra cada pet, se for Cão".

comprehension.py
# list comprehension: TRANSFORMAR e FILTRAR (aula 18)
class Pet:
    def __init__(self, nome, especie):
        self.nome = nome
        self.especie = especie

pets = [Pet("Rex", "Cão"), Pet("Mimi", "Gato"), Pet("Bob", "Cão")]

nomes = [pet.nome for pet in pets]                          # TRANSFORMAR
print(nomes)                        # ['Rex', 'Mimi', 'Bob']

caes = [pet.nome for pet in pets if pet.especie == "Cão"]   # FILTRAR
print(caes)                         # ['Rex', 'Bob']
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 18 · Coleções

sorted × sort, dict.get e set de objetos

sorted() devolve lista nova; .sort() ordena in-place e devolve None. .get() evita KeyError. set só deduplica objetos com __eq__ e __hash__.

colecoes.py
numeros = [3, 1, 2]

ordenada = sorted(numeros)     # sorted() devolve uma lista NOVA (aula 18)
print(ordenada)                # [1, 2, 3]

resultado = numeros.sort()     # .sort() ordena in-place e devolve None
print(resultado)               # None
print(numeros)                 # [1, 2, 3]

estoque = {"P01": "Café", "P02": "Chá"}
print(estoque.get("P01"))          # Café
print(estoque.get("P99"))          # None  — .get() evita KeyError
print(estoque.get("P99", "vazio")) # vazio

# set só deduplica objetos com __eq__ + __hash__ (aula 11 revisitada na 18)
class Pet:
    def __init__(self, nome):
        self.nome = nome
    def __eq__(self, outro):
        return self.nome == outro.nome
    def __hash__(self):
        return hash(self.nome)

unicos = {Pet("Rex"), Pet("Rex"), Pet("Mimi")}
print(len(unicos))             # 2
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 20 · Padrões criacionais

Padrão de projeto e a família criacional

  • 📖 Padrão de projeto é solução pronta, testada e nomeada para um problema recorrente de design OO. É a receita, não o prato pronto.
  • 👔 GoF (Gang of Four): os 4 autores do livro de 1994 que catalogou 23 padrões clássicos, em 3 famílias: criacionais, estruturais e comportamentais.
  • 🏭 Os criacionais cuidam de COMO criar objetos. Nada de Python novo: combinam herança, ABC, polimorfismo e composição já conhecidos.

Singleton

Garante UMA única instância no programa. Controla quantas existem (sempre uma).

Simple Factory

Uma função central decide QUAL classe criar por um parâmetro. Idiom, não é GoF.

Factory Method

A SUBCLASSE do criador decide o produto. A forma GoF do padrão.

Revisão para a 2ª VA — Aulas 14 a 24

Bloco 20 · Padrões criacionais

Singleton via __new__ (prova com is)

O Singleton intercepta __new__ (que roda ANTES do __init__) para devolver sempre a mesma instância. Prova-se com is (identidade), não com ==.

singleton.py
# Singleton: intercepta __new__ para devolver sempre a MESMA instância (aula 20)
class ConfigSistema:
    _instancia = None

    def __new__(cls):
        if cls._instancia is None:
            cls._instancia = super().__new__(cls)
            cls._instancia.tema = "claro"   # estado inicial só na 1ª vez
        return cls._instancia

config1 = ConfigSistema()
config2 = ConfigSistema()

print(config1 is config2)    # True  — prova com is (identidade), não com ==
config1.tema = "escuro"
print(config2.tema)          # escuro  — é o mesmo objeto
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 20 · Padrões criacionais

Simple Factory × Factory Method

Na Simple Factory, uma FUNÇÃO decide a classe por um parâmetro. No Factory Method (GoF), a SUBCLASSE do criador é quem decide o produto.

factory.py
from abc import ABC, abstractmethod

class Calabresa:
    def __str__(self): return "Calabresa"
class Portuguesa:
    def __str__(self): return "Portuguesa"

# Simple Factory: uma função central decide QUAL classe pelo parâmetro (aula 20)
def criar_pizza(sabor):
    tabela = {"calabresa": Calabresa, "portuguesa": Portuguesa}  # guarda CLASSES
    if sabor not in tabela:
        raise ValueError(f"Sabor desconhecido: {sabor}")
    return tabela[sabor]()          # o () instancia a classe escolhida

print(criar_pizza("calabresa"))     # Calabresa

# Factory Method (GoF): a SUBCLASSE do criador decide o produto
class Pizzaria(ABC):
    @abstractmethod
    def criar_pizza(self):
        ...
    def entregar(self):
        return f"Entregando {self.criar_pizza()}"

class PizzariaPaulistana(Pizzaria):
    def criar_pizza(self):
        return Calabresa()

print(PizzariaPaulistana().entregar())   # Entregando Calabresa
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 21 · Padrões comportamentais

Observer × Strategy

Os dois são comportamentais e vivem do mesmo tripé (ABC, polimorfismo, composição). A diferença é a intenção: avisar muitos × delegar a um.

Observer — AVISA muitos

  • 📣 Um Subject mantém uma lista de Observers interessados.
  • 📣 Ao mudar de estado, notificar() percorre a lista e avisa TODOS.
  • 📣 Relação um-para-muitos.
  • 📣 Ecossistema: command= de botão inscreve um observer (Tkinter, aula 22).

Strategy — DELEGA a um

  • 🔀 Cada algoritmo vira uma classe trocável com um método comum.
  • 🔀 Um Contexto guarda UMA estratégia ativa e delega a ela.
  • 🔀 Troca o "como" em runtime sem mudar quem chama.
  • 🔀 Ponte (aula 18): a key do sorted É a estratégia.
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 21 · Padrões comportamentais

Observer: o Subject avisa os inscritos

O Subject (Canal) guarda a lista de inscritos e, ao publicar, chama atualizar() em cada um. Cada Observer implementa o mesmo método.

observer.py
from abc import ABC, abstractmethod

# Observer: o Subject AVISA todos os inscritos ao mudar de estado (aula 21)
class Inscrito(ABC):
    @abstractmethod
    def atualizar(self, video):     # cada Observer implementa atualizar()
        ...

class Canal:                        # Subject / Observável
    def __init__(self, nome):
        self.nome = nome
        self.inscritos = []
    def inscrever(self, inscrito):
        self.inscritos.append(inscrito)
    def publicar(self, video):
        for inscrito in self.inscritos:   # notificar = percorrer a lista
            inscrito.atualizar(video)

class Fa(Inscrito):
    def __init__(self, nome):
        self.nome = nome
    def atualizar(self, video):
        print(f"{self.nome} recebeu: {video}")

canal = Canal("SENAI POO")
canal.inscrever(Fa("Ana"))
canal.inscrever(Fa("Bruno"))
canal.publicar("Aula 21")
# Ana recebeu: Aula 21
# Bruno recebeu: Aula 21
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 21 · Padrões comportamentais

Strategy: trocar o algoritmo em runtime

O Contexto (Carrinho) guarda a estratégia ativa e delega a ela. Trocar a estratégia muda o comportamento sem tocar em quem chama. sorted(key=) é o mesmo padrão.

strategy.py
from abc import ABC, abstractmethod

# Strategy: cada algoritmo é uma classe trocável; o Contexto DELEGA (aula 21)
class Desconto(ABC):
    @abstractmethod
    def calcular(self, valor):
        ...

class SemDesconto(Desconto):
    def calcular(self, valor):
        return valor

class BlackFriday(Desconto):
    def calcular(self, valor):
        return valor * 0.5

class Carrinho:                     # Contexto: guarda a estratégia ativa
    def __init__(self, total, desconto):
        self.total = total
        self.desconto = desconto
    def total_final(self):
        return self.desconto.calcular(self.total)   # delega à estratégia

carrinho = Carrinho(200, SemDesconto())
print(carrinho.total_final())       # 200
carrinho.desconto = BlackFriday()   # troca a estratégia em runtime
print(carrinho.total_final())       # 100.0

# Ponte (aula 18): a key do sorted É a estratégia; sorted é o Contexto
produtos = [{"nome": "Café", "preco": 18}, {"nome": "Chá", "preco": 9}]
print([p["nome"] for p in sorted(produtos, key=lambda p: p["preco"])])
# ['Chá', 'Café']
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 22–23 · Tkinter

Widget é objeto; command= é o Observer

  • 🪟 Widget é objeto: cada Label, Button, Entry e Frame é uma classe instanciada e configurada por kwargs (aula 02). A janela COMPÕE widgets (aula 05).
  • 🔁 mainloop() é o loop de eventos: espera um evento e despacha para o callback registrado. É SEMPRE a última linha.
  • 📣 A ponte de ouro: o command= de um botão É o Observer da aula 21 — botão = Subject, função = observer, clique = notificação. Use import tkinter as tk, nunca import *.

tk.Tk()

A janela raiz. Toda app tem exatamente UMA.

.get()

Lê um Entry — devolve SEMPRE string, mesmo digitando 25. Converta com int().

pack / grid / place

Geometry managers. UM por container: pack+grid juntos dão TclError.

Revisão para a 2ª VA — Aulas 14 a 24

Bloco 22–23 · Tkinter

Janela mínima com botão e callback

A janela raiz, um Label, um Button com command= e o mainloop no fim. O callback reage ao clique — você nunca o chama, o Tk chama.

janela.py
import tkinter as tk               # convenção: nunca from tkinter import * (aula 22)

def ao_clicar():                    # callback = o Observer da aula 21
    rotulo.config(text="Clicado!")
    print("Botão clicado")

janela = tk.Tk()                    # janela raiz — a app tem exatamente UMA
janela.title("Exemplo")

rotulo = tk.Label(janela, text="Aguardando...")   # Label = o print() visual
rotulo.pack(padx=20, pady=10)

# command= recebe a FUNÇÃO como valor (sem parênteses) — clique = notificação
botao = tk.Button(janela, text="Clique", command=ao_clicar)
botao.pack(pady=10)

janela.mainloop()                   # loop de eventos — SEMPRE a última linha
# ao clicar no botão, o terminal mostra: Botão clicado
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 22–23 · Tkinter

A armadilha dos parênteses no command=

A pegadinha que mais cai: os parênteses fazem o Python EXECUTAR a função na montagem, em vez de guardá-la para o clique.

command=ao_clicar() ✗

  • 💀 Com parênteses, a função RODA na montagem da janela.
  • 💀 O botão registra o RETORNO da função (geralmente None).
  • 💀 Resultado: botão morto — clicar não faz nada.
  • 💀 Mesmo erro do bind: a função vai SEM parênteses.

command=ao_clicar ✓

  • Sem parênteses, você passa a função como VALOR.
  • O Tk guarda a referência e chama no clique.
  • Para passar argumento: command=lambda: escolher("Calabresa").
  • Para estado: command=self.ao_clicar (método bound leva o self).
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 22–23 · Tkinter

Listbox, bind, messagebox e App(tk.Tk)

A app inteira herda de tk.Tk (aula 07): self vira a janela, o estado vira atributo, os callbacks viram métodos. O Listbox espelha a lista Python. Multi-tela usa tkraise (aula 23).

app.py
import tkinter as tk
from tkinter import messagebox

# a app inteira herda de tk.Tk (herança da aula 07; padrão da aula 23)
class App(tk.Tk):
    def __init__(self):
        super().__init__()          # obrigatório e PRIMEIRO
        self.clientes = ["Ana", "Bruno", "Carla"]   # a lista é a fonte da verdade

        self.lista = tk.Listbox(self, height=5)     # Listbox = a list visual (aula 18)
        self.lista.pack(padx=10, pady=10)
        self.preencher()
        # bind liga um evento a um callback — o command= generalizado
        self.lista.bind("<<ListboxSelect>>", self.ao_selecionar)

        tk.Button(self, text="Excluir", command=self.excluir).pack(pady=5)

    def preencher(self):
        self.lista.delete(0, tk.END)          # limpa ANTES de reinserir (senão duplica)
        for c in self.clientes:
            self.lista.insert(tk.END, c)      # o Listbox espelha a lista Python

    def ao_selecionar(self, evento):          # o handler recebe o evento
        selecao = self.lista.curselection()   # tupla de índices (vazia se nada)
        if selecao:
            print(self.clientes[selecao[0]])

    def excluir(self):
        selecao = self.lista.curselection()
        if selecao and messagebox.askyesno("Excluir", "Confirma?"):  # askyesno → bool
            del self.clientes[selecao[0]]
            self.preencher()

App().mainloop()                     # um único mainloop para toda a app
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 24 · SQLite

O ritual: connect, execute, commit, close

SQLite é um banco inteiro num arquivo .db, sem servidor. O ritual é o abrir → usar → fechar da aula 17. CREATE TABLE IF NOT EXISTS evita erro na 2ª execução.

banco.py
import sqlite3
from pathlib import Path

BANCO = Path(__file__).parent / "loja.db"   # o .db fica ao lado do script (aula 24)

conexao = sqlite3.connect(BANCO)            # abre (cria o arquivo se não existe)
conexao.execute("""
    CREATE TABLE IF NOT EXISTS produtos (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        nome TEXT NOT NULL,
        preco REAL NOT NULL
    )
""")                                        # IF NOT EXISTS evita erro na 2ª execução
conexao.commit()                            # sem commit(), nada é gravado (erro nº 1)
conexao.close()                             # abrir → usar → fechar (aula 17)
print("Banco pronto")                       # Banco pronto
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 24 · SQLite

CRUD com placeholder ? e WHERE LIKE

Valores de usuário SEMPRE por ? (nunca f-string — evita SQL injection). UPDATE/DELETE sem WHERE valem para TODAS as linhas: o WHERE é o cinto de segurança.

crud.py
import sqlite3

conexao = sqlite3.connect("loja.db")       # abre o arquivo do banco (rode num .db novo pra ver esta saída)
conexao.execute("CREATE TABLE produtos (id INTEGER PRIMARY KEY AUTOINCREMENT, nome TEXT, preco REAL)")

# INSERT com placeholder ? — NUNCA f-string (evita SQL injection, aula 24)
conexao.execute("INSERT INTO produtos (nome, preco) VALUES (?, ?)", ("Caneta azul", 2.5))
conexao.execute("INSERT INTO produtos (nome, preco) VALUES (?, ?)", ("Caneta preta", 2.5))
conexao.execute("INSERT INTO produtos (nome, preco) VALUES (?, ?)", ("Caderno", 15.0))
conexao.commit()

# SELECT com busca parcial: WHERE ... LIKE ?
cursor = conexao.execute("SELECT nome, preco FROM produtos WHERE nome LIKE ?", ("Caneta%",))
print(cursor.fetchall())   # [('Caneta azul', 2.5), ('Caneta preta', 2.5)]

# UPDATE com WHERE (o cinto de segurança — sem ele, altera TODAS as linhas)
conexao.execute("UPDATE produtos SET preco = ? WHERE id = ?", (18.0, 3))
print(conexao.execute("SELECT nome, preco FROM produtos WHERE id = ?", (3,)).fetchone())
# ('Caderno', 18.0)

conexao.close()
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 24 · SQLite

SQL: os cinco comandos do CRUD

item detalhe
CREATE TABLE IF NOT EXISTS Cria a tabela (uma vez). IF NOT EXISTS evita OperationalError na 2ª execução.
INSERT (Create) INSERT INTO produtos (nome, preco) VALUES (?, ?). cursor.lastrowid devolve o id gerado.
SELECT (Read) fetchall() → lista de tuplas; fetchone() → uma tupla ou None. WHERE ... LIKE ? filtra parcial.
UPDATE (Update) UPDATE produtos SET preco = ? WHERE id = ?. Sempre com WHERE.
DELETE (Delete) DELETE FROM produtos WHERE id = ?. Sem WHERE, apaga a tabela inteira.
Revisão para a 2ª VA — Aulas 14 a 24

Bloco 24 · SQLite

ORM manual e o padrão Repositório

  • 🔗 ORM manual é a ponte tupla ↔ objeto: from_row(linha) (@classmethod, tupla → objeto) e to_params() (objeto → tupla para os ?). É o parente do from_dict/to_dict da aula 17.
  • 🗄️ Padrão Repositório junta todo o acesso ao banco numa classe (salvar, listar, buscar_por_id, atualizar, remover). Encapsulamento (aula 04): quem chama nunca vê SQL.
  • 🧭 Paralelo POO: linha = objeto, coluna = atributo, tabela = coleção (aula 18). A GUI da 22/23 consome o Repositório sem saber que existe um banco.

from_row(cls, linha)

@classmethod: id, nome, preco = linha; return cls(nome, preco, id).

to_params(self)

return (self.nome, self.preco) — SEM o id (o banco gera).

Esquecer commit()

Erro nº 1: roda sem erro, mas os dados somem ao reabrir. Igual esquecer salvar_todos (aula 23).

Revisão para a 2ª VA — Aulas 14 a 24

A base sustenta tudo

O que POO 01–12 faz por baixo do conteúdo novo

A 2ª VA é cumulativa: os pilares das aulas 01–12 reaparecem dentro de cada tema novo. Reconhecer isso é meio caminho.

Encapsulamento (04) → validação

@property + @setter com raise ValueError protegem placa, preço, saldo. E o Repositório esconde o SQL.

Herança + super() (07/08)

App(tk.Tk) e TelaClientes(tk.Frame): a app e as telas herdam do Tkinter.

Polimorfismo (09) → print(item)

O Listbox mostra print(item) e cada objeto formata o próprio __str__ — sem if por tipo.

ABC + @abstractmethod (10)

O contrato do Observer, do Strategy e do Factory Method: quem não implementa não instancia.

Composição (05)

Frame compõe widgets (22); container compõe telas (23); o todo cria a parte no próprio __init__.

__str__ e factory (03)

__str__ reaparece no Listbox e no from_row; o @classmethod factory vira from_dict (17) e from_row (24).

Sem a base, o conteúdo novo não para de pé. A prova cobra os dois juntos.
Revisão para a 2ª VA — Aulas 14 a 24

Integração

As pontes entre as aulas

  • 🌉 finally (14) → with (17): o with é o finally automático, que fecha o recurso sozinho.
  • 🏗️ @classmethod factory (03) → from_dict (17) → from_row (24): o mesmo padrão de construtor alternativo, três vezes.
  • 🔀 sorted(key=lambda) (18) É Strategy (21); o command= de botão (22) É Observer (21). Padrão que você já usava com outro nome.
  • 💽 Persistência em .txt (17/23) → tabela SQLite (24): mesma ideia de "lembrar das coisas", banco mais robusto.

Composição em cadeia

objeto no objeto (05) → Frame compõe widgets (22) → container compõe telas (23).

Herança em cadeia

super() (07) → App(tk.Tk) e TelaClientes(tk.Frame) (23).

Encapsulamento em cadeia

@property (04) → o Repositório esconde o SQL (24).

Revisão para a 2ª VA — Aulas 14 a 24

Vocabulário

Glossário relâmpago — termos novos da 2ª VA

A prova cobra o termo técnico, não só o código. Saiba nomear cada um.

raise / try / except

Sinalizar e tratar o erro. else = caminho feliz; finally = sempre.

Exceção customizada

Classe que herda de Exception e fala a língua do domínio.

with open(...)

Abre e fecha o arquivo sozinho. Sempre encoding="utf-8".

list comprehension

[expr for x in col if cond] — transformar e filtrar em uma linha.

sorted(key=...)

Ordena por um critério. Devolve lista nova; .sort() devolve None.

__eq__ + __hash__

O par que faz o set deduplicar objetos.

GoF

Gang of Four: o catálogo de 23 padrões clássicos de 1994.

Singleton / __new__

Uma única instância; prova-se com is (identidade).

Factory / Observer / Strategy

Quem cria / avisa muitos / delega a um algoritmo trocável.

command= (callback)

A função como valor (sem parênteses): o Observer do Tkinter.

Listbox / bind / messagebox

Lista visual / evento nomeado / diálogo (askyesno → bool).

App(tk.Tk) / tkraise

App como classe; tkraise troca de tela sem abrir várias janelas.

placeholder ? / WHERE

SQL seguro; WHERE é o cinto de segurança do UPDATE/DELETE.

ORM manual / Repositório

from_row/to_params; a classe que esconde o SQL.

commit()

Sem ele o INSERT roda, mas os dados somem ao reabrir.

chave primária (id)

A coluna que identifica cada linha; o banco gera (AUTOINCREMENT).

Revisão para a 2ª VA — Aulas 14 a 24

Armadilhas

As pegadinhas que mais caem na 2ª VA

Reconheceu o padrão, você corrige. Treine identificar cada uma antes de ler a resposta.

1

except: pass (engolir o erro)

O bug some da tela, mas continua vivo. Capture específico e trate de verdade.

2

Modo "w" apaga o arquivo

Para anexar sem perder o conteúdo, use "a". E write() não pula linha: coloque o \n.

3

x = lista.sort()

.sort() ordena in-place e devolve None. Para guardar em variável, use sorted().

4

{ } vazio é dict, não set

Para set vazio, use set(). E set de objetos exige __eq__ + __hash__.

5

Fazer o todo herdar da parte

O Acervo TEM itens (composição), não É um item — herdar da parte é o erro. Herança é só quando há relação 'é um'.

6

command=ao_clicar() com parênteses

Executa na montagem e registra None: botão morto. Passe a função sem parênteses.

7

pack + grid no mesmo container

TclError: cannot use geometry manager grid inside . which already has slaves managed by pack. Um gerente por container.

8

f-string no SQL

Abre SQL injection. Valores de usuário SEMPRE por placeholder ?.

9

Esquecer o commit()

O INSERT roda sem erro, mas os dados somem ao reabrir. E UPDATE/DELETE sem WHERE atingem tudo.

Revisão para a 2ª VA — Aulas 14 a 24

Autoavaliação

Você está pronto para a 2ª VA se consegue...

  • Montar o quarteto try / except / else / finally e dizer quando cada um roda.
  • Criar uma exceção customizada que herda de Exception e carrega dados (super().__init__).
  • Ler e gravar um arquivo com with open(..., encoding="utf-8") e escolher entre "r", "w" e "a".
  • Escrever um to_dict/from_dict (ou salvar/carregar) para persistir um objeto.
  • Usar list comprehension para transformar e filtrar, e ordenar objetos com sorted(key=lambda).
  • Escolher entre list, tuple, dict e set — e dar __eq__ + __hash__ a um objeto para o set.
  • Explicar e escrever um Singleton (__new__, prova com is).
  • Diferenciar Simple Factory de Factory Method, e Observer de Strategy.
  • Montar uma janela Tkinter com Button + command= e explicar por que é o Observer.
  • Reconhecer a armadilha command=f() × command=f e a de pack + grid.
  • Escrever o CRUD SQLite com placeholder ? e WHERE, sem esquecer o commit().
  • Explicar o ORM manual (from_row/to_params) e o padrão Repositório.
Revisão para a 2ª VA — Aulas 14 a 24

Resumo em uma linha cada

O essencial dos blocos novos

  • Exceções: raise quem detecta, try/except quem trata; else é o caminho feliz, finally roda sempre.
  • Hierarquia: capturar a classe-mãe (LookupError) pega as filhas (IndexError, KeyError).
  • Arquivos: with fecha sozinho, encoding="utf-8" sempre, "w" apaga e "a" anexa.
  • JSON é mais robusto que texto com separador; json.dump grava dicionários (use to_dict antes).
  • Coleções: list ordenada, tuple imutável, dict por chave, set sem duplicata.
  • sorted() devolve lista nova; .sort() devolve None; .get() evita KeyError.
  • Padrão de projeto é receita nomeada (GoF); criacionais criam, comportamentais comunicam.
  • Singleton garante uma instância (is); Factory decide qual classe; Observer avisa muitos; Strategy delega a um.
  • Tkinter: widget é objeto, mainloop é o loop, command= é o Observer (sem parênteses).
  • Listbox espelha a lista Python; App herda de tk.Tk; tkraise troca de tela.
  • SQLite: connect/execute/commit/close; CRUD com placeholder ?; WHERE é o cinto de segurança; Repositório esconde o SQL.