Programação Orientada a Objetos sem mistério
Classes, herança e encapsulamento construindo um sistema de biblioteca do zero
POO assusta muita gente no começo por causa dos termos — classe, objeto, herança, encapsulamento. Mas a ideia central é simples: agrupar dados e comportamento num mesmo lugar. Vamos construir um sistema de biblioteca do zero para mostrar como isso funciona na prática.
O problema que POO resolve
Imagine representar 3 livros sem POO:
livro1_titulo = "O Senhor dos Anéis"
livro1_autor = "Tolkien"
livro1_disponivel = True
livro2_titulo = "1984"
livro2_autor = "Orwell"
livro2_disponivel = False
Isso fica incontrolável rápido. A solução é criar um molde que define como cada livro se parece — isso é uma classe.
Criando sua primeira classe
class Livro:
def __init__(self, titulo, autor):
self.titulo = titulo
self.autor = autor
self.disponivel = True
def emprestar(self):
if self.disponivel:
self.disponivel = False
return f'"{self.titulo}" emprestado com sucesso.'
return f'"{self.titulo}" já está emprestado.'
def devolver(self):
self.disponivel = True
return f'"{self.titulo}" devolvido. Obrigado!'
Dois conceitos aqui:
__init__é o construtor — roda automaticamente quando você cria um objetoselfé a referência ao próprio objeto — é como ele sabe a diferença entre meus dados e os dados de outro livro
Criando objetos a partir da classe
livro1 = Livro("O Senhor dos Anéis", "Tolkien")
livro2 = Livro("1984", "Orwell")
print(livro1.emprestar()) # "O Senhor dos Anéis" emprestado com sucesso.
print(livro1.emprestar()) # "O Senhor dos Anéis" já está emprestado.
print(livro1.devolver()) # "O Senhor dos Anéis" devolvido. Obrigado!
Herança: reaproveitar sem repetir
E se quisermos um tipo especial de livro — um e-book, que não tem exemplar físico e nunca fica "indisponível"? Herança permite criar uma classe nova que aproveita tudo da anterior e só muda o que precisa.
class Ebook(Livro):
def __init__(self, titulo, autor, formato):
super().__init__(titulo, autor)
self.formato = formato
def emprestar(self):
# E-book pode ser "emprestado" por múltiplas pessoas
return f'"{self.titulo}" ({self.formato}) disponível para download.'
epub = Ebook("Python Fluente", "Ramalho", "EPUB")
print(epub.emprestar()) # "Python Fluente" (EPUB) disponível para download.
print(epub.autor) # Ramalho ← herdado de Livro
Encapsulamento: proteger o estado interno
Em Python, o convênio é usar underscore para sinalizar que um atributo é interno e não deve ser acessado diretamente de fora:
class ContaBancaria:
def __init__(self, saldo_inicial):
self._saldo = saldo_inicial # _ = "use com cuidado"
def depositar(self, valor):
if valor > 0:
self._saldo += valor
def sacar(self, valor):
if valor > self._saldo:
return "Saldo insuficiente."
self._saldo -= valor
return f"Saque de R${valor:.2f} realizado."
@property
def saldo(self):
return self._saldo
conta = ContaBancaria(1000)
conta.depositar(500)
print(conta.sacar(200)) # Saque de R$200.00 realizado.
print(conta.saldo) # 1300
O@propertycria um getter — permite lerconta.saldocomo se fosse um atributo normal, mas por baixo é um método. Útil para validar leitura ou calcular um valor na hora.
Desafio rápido
- Crie uma classe
Alunocom nome, nota1 e nota2. Adicione um métodomedia()que retorna a média e um métodoaprovado()que retornaTruese a média for maior ou igual a 6. - Crie 3 instâncias e imprima o status de aprovação de cada uma.
Próximos passos
Com POO, você tem as ferramentas para organizar qualquer programa de médio porte. O próximo tutorial aplica tudo isso no mundo real: vamos construir uma API REST com Django.