// aula 04 · Python · POO
O que vamos construir
Nessa aula o Guanabara mostra como melhorar uma classe existente aplicando boas práticas de POO, e cria do zero uma classe ContaBancaria — um exemplo clássico para entender atributos, métodos, encapsulamento e controle de estado na prática.
A ideia é sair do exemplo da Caneta (abstrato) e partir para algo mais próximo do mundo real: uma conta com titular, saldo, depósitos e saques.
Por que conta bancária? Porque ela tem tudo que uma boa classe precisa: atributos (saldo, titular), métodos (depositar, sacar), validações (não sacar mais do que tem) e encapsulamento (saldo não deve ser alterado diretamente).
Melhorando uma classe — boas práticas
Atributos públicos — qualquer código pode alterar o saldo diretamente. Sem validação, sem controle. Isso quebra o encapsulamento.
Ex: conta.saldo = -9999 funcionaria sem erro.
Atributos privados com __. Acesso controlado por métodos. Validações dentro dos métodos. O objeto cuida da sua própria integridade.
Ex: conta.sacar(200) verifica o saldo antes de permitir.
O que melhorar em uma classe
Use __atributo para tornar atributos privados. Assim ninguém altera o saldo diretamente de fora da classe.
Coloque if dentro dos métodos para validar antes de executar. Ex: checar se tem saldo antes de sacar.
Defina o método __str__ para que ao fazer print(conta) apareça algo útil ao invés de um endereço de memória.
Estrutura da classe ContaBancaria
__titular — nome do dono da conta__saldo — valor atual disponível__limite — limite de crédito adicional__extrato — histórico de movimentaçõesdepositar(valor) — adiciona ao saldosacar(valor) — remove com validaçãotransferir(valor, destino) — saca e depositaget_saldo() — retorna o saldo atual__str__() — exibe dados da conta| Método | O que faz | Validação |
|---|---|---|
depositar(v) |
Soma v ao saldo e registra no extrato |
Valor deve ser maior que zero |
sacar(v) |
Subtrai v do saldo e registra no extrato |
Saldo + limite deve ser suficiente |
transferir(v, dest) |
Saca desta conta e deposita na conta destino | Mesma validação do saque |
get_saldo() |
Retorna o valor do saldo atual | — |
get_extrato() |
Retorna o histórico de movimentações | — |
Código completo — passo a passo
passo 1 — criando a classe e o construtor
class ContaBancaria: def __init__(self, titular, saldo_inicial=0, limite=0): self.__titular = titular # privado — nome do titular self.__saldo = saldo_inicial # privado — saldo inicial self.__limite = limite # privado — limite de crédito self.__extrato = [] # lista para guardar movimentações self.__extrato.append(f'Conta criada com saldo R$ {saldo_inicial:.2f}')
O construtor (__init__) é chamado automaticamente quando o objeto é criado. Aqui já definimos os atributos com __ (privados) e criamos uma lista de extrato vazia que vai crescer com cada operação.
passo 2 — método depositar
def depositar(self, valor): if valor > 0: self.__saldo += valor self.__extrato.append(f'Depósito: R$ {valor:.2f}') print(f'✅ Depósito de R$ {valor:.2f} realizado.') else: print('❌ Valor de depósito inválido.')
passo 3 — método sacar (com validação)
def sacar(self, valor): saldo_disponivel = self.__saldo + self.__limite if 0 < valor <= saldo_disponivel: self.__saldo -= valor self.__extrato.append(f'Saque: R$ {valor:.2f}') print(f'✅ Saque de R$ {valor:.2f} realizado.') else: print('❌ Saldo insuficiente ou valor inválido.')
passo 4 — método transferir
def transferir(self, valor, conta_destino): saldo_disponivel = self.__saldo + self.__limite if 0 < valor <= saldo_disponivel: self.__saldo -= valor self.__extrato.append(f'Transferência enviada: R$ {valor:.2f}') conta_destino.depositar(valor) print(f'✅ Transferência de R$ {valor:.2f} realizada.') else: print('❌ Saldo insuficiente para transferência.')
passo 5 — getters e __str__
# Getters — acesso controlado aos atributos privados def get_saldo(self): return self.__saldo def get_titular(self): return self.__titular def get_extrato(self): print(f'\n--- Extrato de {self.__titular} ---') for mov in self.__extrato: print(f' {mov}') print(f' Saldo atual: R$ {self.__saldo:.2f}') print('------------------------\n') # __str__ — o que aparece ao fazer print(conta) def __str__(self): return (f'ContaBancaria | Titular: {self.__titular} | ' f'Saldo: R$ {self.__saldo:.2f} | Limite: R$ {self.__limite:.2f}')
usando a classe — exemplo completo
# Criando as contas conta_lucilia = ContaBancaria('Lucilia', saldo_inicial=1000, limite=500) conta_vini = ContaBancaria('Vinicius', saldo_inicial=300) # Operações conta_lucilia.depositar(500) # ✅ Depósito de R$ 500.00 realizado. conta_lucilia.sacar(200) # ✅ Saque de R$ 200.00 realizado. conta_lucilia.transferir(100, conta_vini) # ✅ Transferência realizada. conta_lucilia.sacar(9999) # ❌ Saldo insuficiente. # Ver extrato conta_lucilia.get_extrato() # print() usa o __str__ print(conta_lucilia) # ContaBancaria | Titular: Lucilia | Saldo: R$ 1200.00 | Limite: R$ 500.00
Os pilares da POO na prática — ContaBancaria
Uma conta bancária real tem dezenas de atributos. Aqui modelamos só o necessário: titular, saldo, limite e extrato. O resto não importa para o nosso programa.
O __saldo é privado. Ninguém faz conta.saldo = -999. Só depositar() e sacar() alteram o saldo — e com validação.
Poderíamos criar ContaCorrente e ContaPoupanca herdando de ContaBancaria, cada uma com suas particularidades, sem reescrever tudo.
Uma ContaPoupanca poderia ter seu próprio sacar() com regras diferentes (ex: só 1 saque por mês), mesmo herdando da classe base.
Dunder attributes — métodos especiais do Python
Dunder vem de Double UNDERscore — os métodos com __duplo_underscore__ antes e depois do nome. O Python os chama automaticamente em situações específicas, sem você precisar invocar diretamente.
Você já usou dois nessa aula: __init__ (construtor) e __str__ (representação). Mas existem vários outros que deixam sua classe muito mais poderosa.
Dunder não é nome bonito — é uma convenção do Python para separar métodos especiais (que o interpretador chama) dos métodos normais (que você chama). Nunca crie métodos com __nome__ por conta própria.
Chamado automaticamente quando o objeto é criado. Define os atributos iniciais.
Ativado por: ContaBancaria('Lucilia')
Chamado quando você faz print(obj) ou str(obj). Deve retornar uma string amigável.
Ativado por: print(conta)
Usado no console interativo e em logs. Deve retornar uma string que idealmente recrie o objeto.
Ativado por: digitar conta no console
Chamado quando você usa len(obj). Útil para classes que representam coleções.
Ativado por: len(conta)
Define o que acontece ao usar == entre dois objetos. Sem ele, Python compara os endereços de memória.
Ativado por: conta1 == conta2
Chamado quando o objeto é destruído (removido da memória). Raramente necessário no dia a dia.
Ativado por: del conta
exemplo — dunder na ContaBancaria
class ContaBancaria: def __init__(self, titular, saldo_inicial=0): self.__titular = titular self.__saldo = saldo_inicial self.__extrato = [] # Representação amigável — para print() def __str__(self): return f'Conta de {self.__titular} | Saldo: R$ {self.__saldo:.2f}' # Representação técnica — para o console def __repr__(self): return f"ContaBancaria('{self.__titular}', {self.__saldo})" # Tamanho — retorna quantas movimentações tem no extrato def __len__(self): return len(self.__extrato) # Igualdade — duas contas são iguais se tiverem o mesmo titular def __eq__(self, outra): return self.__titular == outra.get_titular() # Testando os dunders c1 = ContaBancaria('Lucilia', 1000) c2 = ContaBancaria('Vinicius', 300) print(c1) # → Conta de Lucilia | Saldo: R$ 1000.00 repr(c1) # → ContaBancaria('Lucilia', 1000) len(c1) # → 0 (nenhuma movimentação ainda) print(c1 == c2) # → False
Erros comuns nessa aula
Esquecer o __ antes do atributo. Com self.saldo (público), qualquer código pode fazer conta.saldo = -1000 sem validação.
Todo método de instância precisa de self como primeiro parâmetro. Sem ele o Python não sabe de qual objeto está falando.
Fazer conta.__saldo de fora da classe gera AttributeError. Use sempre o getter: conta.get_saldo().
Sem __str__, fazer print(conta) mostra algo como <__main__.ContaBancaria object at 0x...> — inútil para debug.