This content is only available in Portuguese.

Also available in English.

View translation
Code & Development

Orientação a Objetos em Python: pra quem já travou tentando aprender isso

Você já sentiu que entendeu as palavras de OOP, mas não entendeu nada? Não é falta de talento. Alguém te entregou a chave antes de te mostrar o cadeado. Este artigo corrige isso, revelando o problema real que a Orientação a Objetos em Python resolve. Deixe de lado a sintaxe e entenda o porquê de classes, herança, encapsulamento e polimorfismo existirem, com exemplos práticos.

Equipe Blueprintblog7 min
Orientação a Objetos em Python: pra quem já travou tentando aprender isso

Você não travou porque OOP é difícil. Travou porque ninguém te mostrou o problema antes de te entregar a solução. Esse artigo corrige isso — de verdade.

Primeiro, uma pergunta honesta

Você já chegou na parte de "orientação a objetos" de algum tutorial e sentiu aquela coisa específica — a sensação de que entendeu as palavras mas não entendeu nada?

Você lia: "uma classe é um molde para criar objetos". Fazia sentido na superfície. Mas ficava aquela pergunta sem resposta: por que eu precisaria disso? Quando usaria? O meu código funciona sem isso...

Essa sensação não é falta de talento. É o sinal de que alguém te entregou a chave antes de te mostrar o cadeado.

A ideia do cadeado e da chave: não faz sentido criar uma chave e sair procurando um cadeado. O caminho certo é encontrar um cadeado real — um problema que você já sente — e aí a chave faz todo sentido.

Então vamos começar do problema. Não da solução.

O problema que você vai sentir em breve

Imagina que você tá construindo um sistema pra uma pet shop. Pequeno, só pra aprender. Você começa assim:

text
# Parece ok no começo...
gato1_nome = "Whiskers"
gato1_idade = 3
gato1_dono = "Ana"

cachorro1_nome = "Rex"
cachorro1_idade = 5
cachorro1_dono = "Bruno"

Funciona. Por enquanto. Mas aí você adiciona mais animais. E mais. E começa a precisar de funções. E de atualizar dados. E a qualquer momento que você olha pro código, tem um barulho de fundo que diz: isso não tá certo.

Esse barulho tem nome: falta de estrutura. E é exatamente aí que OOP existe pra te ajudar.

Não pra deixar o código "mais elegante". Pra resolver essa dor específica que você acabou de imaginar — e que vai sentir de verdade no seu próximo projeto.

A classe: um molde que faz sentido

Uma classe é uma forma de dizer pro Python: "esse conjunto de dados e comportamentos andam juntos, e têm um nome."

Pensa numa ficha cadastral de animal. Ela sempre tem nome, idade e dono. E ela sempre pode ser atualizada, consultada, impressa. A classe é essa ficha — e cada animal que você cadastra é uma cópia preenchida dela.

python
class Animal:
    def __init__(self, nome, idade, dono):
        # __init__ roda automaticamente quando você cria o animal
        self.nome = nome
        self.idade = idade
        self.dono = dono

    def apresentar(self):
        print(f"{self.nome}, {self.idade} anos — dono: {self.dono}")


# Agora criar 100 animais é simples, limpo e consistente
gato = Animal("Whiskers", 3, "Ana")
cachorro = Animal("Rex", 5, "Bruno")

gato.apresentar()     # Whiskers, 3 anos — dono: Ana
cachorro.apresentar() # Rex, 5 anos — dono: Bruno

Sobre o self: é a forma do Python dizer "eu mesmo". Quando você chama gato.apresentar(), o Python passa o próprio gato como primeiro argumento automaticamente. Você declara, mas não passa manualmente. Parece estranho no começo — fica natural em horas.

Os quatro pilares — sem mistério

OOP tem quatro conceitos que aparecem em todo lugar. Antes de ver o código, entenda o porquê de cada um existir:

01

Herança

Evitar reescrever o que já existe. Filha herda da mãe.

02

Encapsulamento

Proteger dados internos. Expor só o que precisa ser exposto.

03

Polimorfismo

Mesma chamada, resultados diferentes. Código flexível.

04

Abstração

Esconder complexidade. Mostrar só o essencial pra quem usa.

Herança — porque repetir código é uma armadilha

Você tem Animal. Agora quer criar Gato e Cachorro com comportamentos específicos — mas sem reescrever nome, idade e dono de novo. Herança resolve isso:

python
class Gato(Animal):  # herda tudo de Animal
    def falar(self):
        print(f"{self.nome} diz: miau 🐱")

    def apresentar(self):  # sobrescreve o método da mãe
        super().apresentar()  # ainda chama o da mãe
        print("...sou bem independente, aliás. 😼")


class Cachorro(Animal):
    def falar(self):
        print(f"{self.nome} diz: au au 🐶")


whiskers = Gato("Whiskers", 3, "Ana")
rex = Cachorro("Rex", 5, "Bruno")

whiskers.apresentar()  # usa o apresentar sobrescrito
rex.falar()            # Rex diz: au au 🐶

Encapsulamento — porque nem tudo deve ser acessado diretamente

Pensa numa conta bancária. O saldo existe, mas ninguém de fora deveria poder escrever conta.saldo = 999999 diretamente. O encapsulamento cria essa proteção:

python
class ContaBancaria:
    def __init__(self, titular, saldo):
        self.titular = titular
        self.__saldo = saldo  # __ = privado, ninguém acessa direto

    def depositar(self, valor):
        if valor > 0:
            self.__saldo += valor
            print(f"Depósito de R${valor:.2f} realizado ✅")

    def sacar(self, valor):
        if valor > self.__saldo:
            print("Saldo insuficiente ❌")
        else:
            self.__saldo -= valor
            print(f"Saque de R${valor:.2f} realizado ✅")

    def ver_saldo(self):
        return f"R${self.__saldo:.2f}"


conta = ContaBancaria("Ana", 1000)
conta.depositar(500)
conta.sacar(200)
print(conta.ver_saldo())  # R$1300.00

# conta.__saldo → AttributeError. Protegido. 🔒

Detalhe que faz diferença: __atributo (dois underscores) bloqueia o acesso externo de verdade — Python renomeia internamente. _atributo (um underscore) é só uma convenção: "use com cuidado", mas não bloqueia tecnicamente.

Polimorfismo — a mesma chamada, cada objeto respondendo do seu jeito

Essa é a parte que parece mágica quando você entende. Você chama .enviar() em qualquer objeto do sistema — e cada um sabe o que fazer:

python
class Notificacao:
    def __init__(self, destino, mensagem):
        self.destino = destino
        self._mensagem = mensagem

    def enviar(self):
        raise NotImplementedError("Implemente nas subclasses")


class Email(Notificacao):
    def enviar(self):
        print(f"📧 Email → {self.destino}: {self._mensagem}")


class SMS(Notificacao):
    def enviar(self):
        print(f"📱 SMS → {self.destino}: {self._mensagem}")


class Push(Notificacao):
    def enviar(self):
        print(f"🔔 Push → {self.destino}: {self._mensagem}")


# Polimorfismo: mesma função, três comportamentos diferentes
def disparar(fila):
    for n in fila:
        n.enviar()

disparar([
    Email("ana@email.com", "Novo artigo no Blueprint Blog!"),
    SMS("+55 22 99999-0000", "Confere lá 📲"),
    Push("user-42", "Não perde esse 🔥"),
])

Por que isso importa: amanhã você quer adicionar WhatsApp. Cria class WhatsApp(Notificacao), implementa enviar(), e joga na fila. O resto do código não muda nada. Isso é o poder real do polimorfismo.

Você aprendeu OOP. Mas o que você realmente ganhou?

Não foi só sintaxe nova. Você ganhou uma forma de pensar sobre código que vai mudar como você organiza qualquer projeto daqui pra frente.

Quando você olha pra um problema agora, começa a perguntar: quais são as entidades aqui? O que elas têm em comum? O que é específico de cada uma? Esse raciocínio é o que separa código que dura de código que você abandona.

O que ficou

  • Classe é o molde. Objeto é o que você cria a partir dele.
  • __init__ inicializa os atributos. self é a referência ao próprio objeto.
  • Herança : filha herda da mãe, sem repetir código.
  • Encapsulamento : protege dados com __ ou _ . Controla o acesso.
  • Polimorfismo : mesma chamada, cada classe responde diferente.
  • OOP não é sobre elegância. É sobre não se perder no seu próprio código quando ele cresce.

Article tags

Related articles

Get the latest articles delivered to your inbox.

Follow Us: