🌗 ← Índice

🐍 Python P11 — Classes e Objetos


Data: 30/07/2026

Nível: Intermediário (Início do Mês 2 — POO)




Até aqui tu escreveu código procedural: funções que recebem dados e devolvem resultados. Hoje começa o Mês 2 com Programação Orientada a Objetos (POO) — o jeito de organizar código que o Python usa por dentro em tudo: listas, arquivos, requests. Entender classes é entender a linguagem.




🎯 O que vamos aprender


  • O que é uma classe e o que é um objeto
  • Atributos (dados) e métodos (comportamentos)
  • `__init__` e `self` — o construtor e a referência
  • Atributos de classe vs atributos de instância
  • Métodos que recebem parâmetros e retornam valores
  • Encapsulamento básico (convenção `_privado`)



  • 🏗️ Classe vs Objeto — a analogia da forma


    Uma classe é uma forma (molde). Um objeto é o bolo que você faz com ela.


    
    # CLASSE = molde (define o que TODO bolo tem e faz)
    class Bolo:
        def __init__(self, sabor, cobertura):
            self.sabor = sabor
            self.cobertura = cobertura
    
        def descrever(self):
            return f"Bolo de {self.sabor} com {self.cobertura}"
    
    # OBJETOS = bolos concretos criados do molde
    bolo1 = Bolo("chocolate", "brigadeiro")
    bolo2 = Bolo("cenoura", "chocolate")
    
    print(bolo1.descrever())  # Bolo de chocolate com brigadeiro
    print(bolo2.descrever())  # Bolo de cenoura com chocolate
    

    Mesmo molde, objetos diferentes — cada um guarda os seus valores. Isso é POO na essência.




    🔑 `__init__` e `self` — os dois pilares


    `__init__` é o construtor: roda automaticamente quando você cria um objeto. É ali que você "inicializa" o objeto.

    `self` é a referência ao próprio objeto. Ele é sempre o primeiro parâmetro de todo método — é assim que o método sabe em qual objeto está mexendo.


    
    class Usuario:
        def __init__(self, nome, email):
            self.nome = nome        # atributo de instância
            self.email = email      # atributo de instância
            self.logado = False     # valor padrão
    
        def login(self):
            self.logado = True
            print(f"{self.nome} entrou!")
    
        def logout(self):
            self.logado = False
            print(f"{self.nome} saiu.")
    
    u = Usuario("Hugo", "hugo@hbstudio.com.br")
    print(u.nome)        # Hugo
    print(u.logado)      # False
    u.login()            # Hugo entrou!
    print(u.logado)      # True
    

    💡 Sem `self` o método não sabe QUAL usuário está logando. Com `self`, cada objeto mexe nos próprios dados.



    📦 Atributos de classe vs de instância


    Instância (com `self.`): cada objeto tem o seu — valor muda de um pra outro.

    Classe (sem `self.`): é compartilhado por todos os objetos — igual a um cartaz na parede da fábrica.


    
    class Contador:
        total_instancias = 0          # atributo de CLASSE (compartilhado)
    
        def __init__(self, nome):
            self.nome = nome          # atributo de INSTÂNCIA (individual)
            Contador.total_instancias += 1
    
    c1 = Contador("primeiro")
    c2 = Contador("segundo")
    print(Contador.total_instancias)  # 2 (a classe conta todos)
    print(c1.nome)                    # primeiro
    print(c2.nome)                    # segundo
    



    ⚙️ Métodos com parâmetros e retorno


    Método é só uma função que vive dentro da classe — pode receber parâmetros e retornar valores normalmente.


    
    class Calculadora:
        def somar(self, a, b):
            return a + b
    
        def dividir(self, a, b):
            if b == 0:
                return "Erro: divisão por zero"
            return a / b
    
    calc = Calculadora()
    print(calc.somar(5, 3))     # 8
    print(calc.dividir(10, 2))  # 5.0
    print(calc.dividir(1, 0))   # Erro: divisão por zero
    



    🔒 Encapsulamento — a convenção do sublinhado


    Em Python não existe `private` de verdade (isso é Java). Usa-se convenção: atributos com `_` na frente são "internos" — ninguém deve mexer de fora.


    
    class ContaBancaria:
        def __init__(self, titular, saldo):
            self.titular = titular
            self._saldo = saldo          # "privado" por convenção
    
        def depositar(self, valor):
            if valor > 0:
                self._saldo += valor
    
        def sacar(self, valor):
            if valor > 0 and valor <= self._saldo:
                self._saldo -= valor
                return True
            return False
    
        def ver_saldo(self):
            return self._saldo
    
    conta = ContaBancaria("Hugo", 1000)
    conta.depositar(500)
    print(conta.ver_saldo())   # 1500
    print(conta.sacar(2000))   # False (não tem saldo)
    print(conta.ver_saldo())   # 1500
    

    💡 Acessar `conta._saldo` direto funciona, mas é quebra de contrato. A regra: métodos mudam dados, atributos privados não são tocados de fora.



    ✍️ Exercícios (15 min)


  • E1: Crie uma classe `Livro` com `titulo`, `autor` e `paginas`. Adicione um método `resumo()` que retorna `" por páginas"`. Crie 2 livros e imprima os resumos.
  • E2: Crie uma classe `Cachorro` com `nome`, `idade` e um método `latir()` que imprime `": Au au!"`. Crie um cachorro, aumente a idade dele e faça-o latir.
  • E3: Adicione um atributo de classe `especie = "Canis familiaris"` na classe `Cachorro` e imprima `Cachorro.especie` e `rex.especie` — repare que os dois dão o mesmo valor.



  • 🧪 Desafio (15 min)


    Crie uma classe `Banco` que gerencia várias contas:


  • Classe `Conta` com `numero`, `titular` e `_saldo`
  • Métodos `depositar(valor)`, `sacar(valor)` e `ver_saldo()`
  • Classe `Banco` com método `criar_conta(numero, titular, saldo_inicial)` que guarda as contas numa lista
  • Método `transferir(origem, destino, valor)` que saca de uma e deposita na outra
  • Método `total_banco()` que soma o saldo de todas as contas

  • Teste: crie 2 contas, transfira R$ 200 da conta 1 pra conta 2 e mostre os saldos e o total.




    ✅ Correção (10 min)


    Mostrar gabarito E1
    
    class Livro:
        def __init__(self, titulo, autor, paginas):
            self.titulo = titulo
            self.autor = autor
            self.paginas = paginas
    
        def resumo(self):
            return f"{self.titulo} por {self.autor} — {self.paginas} páginas"
    
    livro1 = Livro("O Alquimista", "Paulo Coelho", 208)
    livro2 = Livro("Clean Code", "Robert C. Martin", 431)
    print(livro1.resumo())
    print(livro2.resumo())
    

    Mostrar gabarito E2 e E3
    
    class Cachorro:
        especie = "Canis familiaris"   # atributo de classe
    
        def __init__(self, nome, idade):
            self.nome = nome
            self.idade = idade
    
        def latir(self):
            print(f"{self.nome}: Au au!")
    
    rex = Cachorro("Rex", 3)
    rex.idade = 4                      # atualiza a idade do objeto
    rex.latir()                        # Rex: Au au!
    print(rex.especie)                 # Canis familiaris
    print(Cachorro.especie)            # Canis familiaris
    

    Mostrar gabarito Desafio
    
    class Conta:
        def __init__(self, numero, titular, saldo):
            self.numero = numero
            self.titular = titular
            self._saldo = saldo
    
        def depositar(self, valor):
            if valor > 0:
                self._saldo += valor
    
        def sacar(self, valor):
            if valor > 0 and valor <= self._saldo:
                self._saldo -= valor
                return True
            return False
    
        def ver_saldo(self):
            return self._saldo
    
    class Banco:
        def __init__(self, nome):
            self.nome = nome
            self.contas = []
    
        def criar_conta(self, numero, titular, saldo_inicial):
            conta = Conta(numero, titular, saldo_inicial)
            self.contas.append(conta)
            return conta
    
        def transferir(self, origem, destino, valor):
            if origem.sacar(valor):
                destino.depositar(valor)
                return True
            return False
    
        def total_banco(self):
            return sum(c.ver_saldo() for c in self.contas)
    
    banco = Banco("HB Bank")
    c1 = banco.criar_conta(1, "Hugo", 1000)
    c2 = banco.criar_conta(2, "Maria", 500)
    
    print(banco.transferir(c1, c2, 200))   # True
    print(c1.ver_saldo())                  # 800
    print(c2.ver_saldo())                  # 700
    print(banco.total_banco())             # 1500
    



    📌 Resumo da aula


    ConceitoO que éExemplo
    ClasseMolde / definiçãoclass Conta:
    ObjetoInstância criada do moldeconta = Conta(1, "Hugo", 1000)
    __init__Construtor, roda na criaçãodef __init__(self, ...):
    selfReferência ao próprio objetoself._saldo = saldo
    AtributoDado do objetoself.titular
    MétodoFunção do objetodef sacar(self, valor)
    EncapsulamentoConvenção `_` = internoself._saldo



    Próxima aula: Herança e Polimorfismo — `super()`, reutilizar e especializar classes. 🧬


    ← Voltar ao índice