Guia de estudo

06/05/2026 · Aula 09

Polimorfismo

A mesma ordem. Reações diferentes.

Programação Orientada a Objetos com Python
Tecnologia em Análise e Desenvolvimento de Sistemas

Por que polimorfismo existe? Polimorfismo por Herança Duck Typing Dunder Methods

plano de voo

O que vamos aprender hoje

01

O Problema

Por que código sem polimorfismo se torna um pesadelo.

02

O Conceito

O que é polimorfismo de verdade, sem jargão.

03

As Formas

Polimorfismo por herança e Duck Typing — quando usar cada um.

04

Na Prática

Sistemas reais que usam polimorfismo sem você perceber.

conexão com a aula anterior

Você já fez a base. Hoje vê o resultado.

  • 🔙 Aula 08 — Sobrescrita: Subclasses podem redefinir métodos da classe pai com suas próprias implementações.
  • ➡️ Hoje — Polimorfismo: Quando chamamos o mesmo método em objetos diferentes, cada um executa a sua versão. Esse comportamento tem um nome.

A Relação Direta

Sobrescrita (override) é o mecanismo. Polimorfismo é o resultado que enxergamos de fora.

começando pelo problema

Imagine um sistema sem polimorfismo

  • 😬 Para cada tipo novo de funcionário, você precisa abrir esse código e adicionar mais um elif.
  • 💥 Se esquecer de atualizar, o sistema silenciosamente calcula errado — sem erro, sem aviso.

Regra prática

Se você tem if/elif verificando tipos de objetos para decidir o que fazer — seu código está pedindo polimorfismo.

o problema em código

O if/elif que nunca para de crescer

Veja o que acontece quando você tem 3 tipos de funcionário e não usa polimorfismo.

🔴
O parâmetro tipo existe só para compensar a falta de polimorfismo.
🔴
Cada novo tipo de funcionário = editar essa função. Para sempre.
sem_polimorfismo.py
class Clt:
    def __init__(self, salario_base):
        self.salario_base = salario_base

class Freelancer:
    def __init__(self, valor_hora, horas):
        self.valor_hora = valor_hora
        self.horas = horas

class Socio:
    def __init__(self, lucro, percentual):
        self.lucro = lucro
        self.percentual = percentual

# Toda a lógica centralizada aqui — e presa aqui para sempre
def calcular_pagamento(funcionario, tipo):
    if tipo == 'clt':
        return funcionario.salario_base
    elif tipo == 'freelancer':
        return funcionario.valor_hora * funcionario.horas
    elif tipo == 'socio':
        return funcionario.lucro * funcionario.percentual
    # novo tipo? precisa editar aqui. sempre.

a solução

E se cada objeto soubesse calcular o próprio salário?

  • 💡 Pergunta-chave: Por que a função calcular_pagamento precisa saber como cada tipo de funcionário é pago?
  • 🎯 Resposta: Não precisa. Cada classe deveria ser responsável pelo seu próprio comportamento.

O princípio

Mova a lógica para dentro da classe. Deixe o objeto responsável por saber o que fazer quando você mandar a mesma ordem.

a solução em código

Cada classe sabe calcular o próprio salário

Movemos a lógica para dentro de cada classe. Todas têm o mesmo método — mas cada uma implementa do seu jeito.

Cada classe tem o mesmo nome de métodocalcular_salario() — mas com lógica própria.
Nenhuma classe sabe da existência das outras. Cada uma é responsável só por si mesma.
com_polimorfismo.py
class Clt:
    def __init__(self, salario_base):
        self.salario_base = salario_base
    def calcular_salario(self):
        return self.salario_base

class Freelancer:
    def __init__(self, valor_hora, horas):
        self.valor_hora = valor_hora
        self.horas = horas
    def calcular_salario(self):
        return self.valor_hora * self.horas

class Socio:
    def __init__(self, lucro, percentual):
        self.lucro = lucro
        self.percentual = percentual
    def calcular_salario(self):
        return self.lucro * self.percentual

o resultado do polimorfismo

Agora veja o que acontece do lado de fora

Com o polimorfismo no lugar, o código que usa os objetos fica radicalmente mais simples — e nunca mais precisa ser alterado.

🟢
O loop não sabe e não precisa saber qual tipo de funcionário está processando.
🟢
Quer adicionar um novo tipo? Crie a classe com calcular_salario() e adicione na lista. Zero mudança no loop.
usando_polimorfismo.py
funcionarios = [
    Clt(3000),
    Freelancer(80, 40),
    Socio(50000, 0.05),
    Clt(4500),            # novo clt? só adicionar na lista
]

# Mesmo comando para todos. Cada um responde do seu jeito.
for f in funcionarios:
    print(f.calcular_salario())

# Saída:
# 3000
# 3200
# 2500.0
# 4500

definição

Agora podemos dar o nome

  • 🎭 Poly = muitos. Morphos = formas. Muitas formas de responder à mesma mensagem.
  • 📌 Na prática: mesmo nome de método em classes diferentes. Cada objeto executa a sua versão quando chamado.

As três camadas do polimorfismo

1️⃣ Cada classe tem o método com o mesmo nome.

2️⃣ Você cria uma lista com objetos de tipos diferentes.

3️⃣ Você chama o método em todos — sem if, sem perguntar quem é quem.

antes e depois · lado a lado

A diferença que o polimorfismo faz

❌ Sem Polimorfismo

  • Função central cheia de if/elif
  • Novo tipo = editar código existente
  • Lógica espalhada fora dos objetos
  • Fácil esquecer de um caso

✅ Com Polimorfismo

  • Loop simples, sem condicionais
  • Novo tipo = nova classe, nada mais
  • Cada objeto carrega sua própria lógica
  • Impossível esquecer: a classe define

exemplo do cotidiano

Polimorfismo existe no mundo real

  • ▶️ Botão Play: Funciona no Spotify, no YouTube, no Netflix. O botão é o mesmo — cada plataforma executa do seu jeito.
  • 💳 Maquininha de cartão: Aceita crédito, débito, Pix, VR. O processo de 'pagar' é o mesmo comando — cada bandeira tem sua lógica interna.

A analogia

Você, como usuário, manda a mesma ordem. O sistema não te pergunta 'qual bandeira você quer usar para processar?'. Ele simplesmente processa — cada objeto do jeito que sabe.

as duas formas de polimorfismo em python

Existem dois caminhos para chegar lá

  • 🌳 Por Herança: Classes compartilham um ancestral comum. O pai 'promete' que o método existe. Filhos entregam a versão deles.
  • 🦆 Duck Typing: Sem parentesco. Se o objeto tem o método que você precisa, ele funciona. Python não verifica a família.

Qual usar?

Herança quando os objetos têm parentesco lógico real (Cão é Animal). Duck Typing quando objetos não relacionados precisam responder ao mesmo comando.

polimorfismo por herança

Caminho 1: A Hierarquia como Contrato

  • 📜 Contrato: A classe pai declara o método. Isso é uma 'promessa' de que todos os filhos vão ter esse método disponível.
  • 🔀 Especialização: Cada filha sobrescreve com sua lógica própria — sem mudar o nome, sem mudar a assinatura.

Regra crítica

O nome do método precisa ser idêntico em todas as classes da hierarquia. É o nome que garante a interface comum.

herança · exemplo clássico

Animais com sons diferentes

Todos são animais. Todos 'falam'. Cada um fala do seu jeito.

🎯
O loop não sabe e não precisa saber se é cachorro ou gato. Só manda falar().
Quer adicionar Leão? Crie a classe Leao(Animal) com falar(). O loop já funciona com ela — sem alterar nada.
animais.py
class Animal:
    def falar(self):
        pass  # a classe pai apenas declara que o método existe

class Cachorro(Animal):
    def falar(self):
        print("Au! Au!")

class Gato(Animal):
    def falar(self):
        print("Miau!")

class Papagaio(Animal):
    def falar(self):
        print("Quem vive, vê!")

# Polimorfismo em ação:
animais = [Cachorro(), Gato(), Papagaio(), Cachorro()]

for animal in animais:
    animal.falar()  # mesma ordem — reações diferentes

herança · formas geométricas

Formas com áreas diferentes

O exemplo clássico da literatura de POO — funciona muito bem para mostrar o conceito.

⚠️
A classe Forma base retorna 0 — subclasses que esquecerem de implementar area() vão herdar esse zero silenciosamente.
🔜
Prévia — Aula 10: Classes Abstratas (ABC) vão forçar que toda subclasse implemente o método, ou o Python vai reclamar.
formas.py
class Forma:
    def area(self):
        return 0  # ⚠️ provisório — Aula 10 resolve com ABC

class Quadrado(Forma):
    def __init__(self, lado):
        self.lado = lado
    def area(self):
        return self.lado ** 2

class Circulo(Forma):
    def __init__(self, raio):
        self.raio = raio
    def area(self):
        return 3.14 * (self.raio ** 2)

class Triangulo(Forma):
    def __init__(self, base, altura):
        self.base = base
        self.altura = altura
    def area(self):
        return (self.base * self.altura) / 2

formas = [Quadrado(4), Circulo(3), Triangulo(6, 4)]

for f in formas:
    print(f"Área: {f.area()}")  # mesma chamada, resultados diferentes

por que isso importa

O que o polimorfismo entrega

🚀

Extensível por natureza

Adicione um novo tipo criando uma nova classe. O restante do sistema não precisa ser tocado.

🧹

Zero if/elif de tipo

Não existe mais 'se é X faça isso, se é Y faça aquilo'. Os objetos se viram sozinhos.

🧩

Desacoplamento real

Quem usa os objetos não precisa conhecer os detalhes internos de cada um. Só precisa saber o nome do método.

duck typing — caminho 2

Python não liga para família. Liga para comportamento.

  • 🦆 A frase que define: 'Se caminha como um pato e faz quack como um pato — então é um pato.' Python não verifica a certidão de nascimento.
  • 🔍 Em código: Python não checa se o objeto pertence a uma hierarquia. Ele simplesmente tenta chamar o método. Se funcionar — funcionou.

A diferença para Java ou C#

Nessas linguagens, para ter polimorfismo você obrigatoriamente precisa herdar de uma classe base ou implementar uma interface. Em Python, basta ter o método.

duck typing · o clássico do pato

Objetos sem parentesco — comportamento igual

Pato e Pessoa não têm nenhuma relação de herança. Mas ambos sabem fazer quack — e isso é suficiente.

🦆
Pessoa não herda de Pato. Não existe classe base em comum. Não importa.
O Python só pergunta uma coisa: 'esse objeto tem o método quack()?' Se sim, executa.
duck_typing.py
class Pato:
    def quack(self):
        print("Quack! Quack!")

class Pessoa:
    def quack(self):
        print("Eu estou imitando um pato!")

# Nenhuma herança. Nem precisamos.
# Se tem quack() — funciona.
def faz_quack(objeto):
    objeto.quack()

faz_quack(Pato())    # Quack! Quack!
faz_quack(Pessoa())  # Eu estou imitando um pato!

duck typing · sistema real

Pagamentos sem herança obrigatória

Três formas de pagar. Nenhuma herança. Puro Duck Typing.

🧩
Quer adicionar Cripto? Crie a classe com pagar(). A função finalizar_venda já funciona com ela.
📌
A função finalizar_venda não sabe — e não precisa saber — qual tipo de pagamento está recebendo.
pagamentos_duck.py
class Pix:
    def pagar(self, valor):
        print(f"QR Code gerado — R$ {valor:.2f}")

class CartaoCredito:
    def __init__(self, final):
        self.final = final
    def pagar(self, valor):
        print(f"Cartão {self.final} autorizado — R$ {valor:.2f}")

class Boleto:
    def pagar(self, valor):
        print(f"Boleto gerado — R$ {valor:.2f} (vence em 3 dias)")

# Nenhuma herança. Todos têm pagar(). Isso basta.
def finalizar_venda(metodo, total):
    metodo.pagar(total)

finalizar_venda(Pix(), 150.00)
finalizar_venda(CartaoCredito("1234"), 300.00)
finalizar_venda(Boleto(), 89.90)

duck typing · cuidado

O que acontece se o método não existir?

  • 💥 AttributeError: É o erro que Python lança quando você tenta chamar um método que o objeto não tem.
  • 🛡️ Como se proteger: Existem duas abordagens — verificar antes de chamar (hasattr) ou tentar e tratar o erro (try/except).

Não é fraqueza — é escolha

Em código bem escrito com Duck Typing, você sabe quais objetos vai receber. O tratamento de erro é para casos externos — APIs, dados de usuário, plugins.

duck typing · tratamento de erro

As duas formas seguras de usar Duck Typing

LBYL verifica antes. EAFP tenta e trata. O Python prefere EAFP — mas LBYL tem seu lugar.

🔍
LBYL com hasattr(): Mais explícito. Bom quando receber um objeto sem o método é um caso comum esperado.
🐍
EAFP com try/except: O estilo preferido do Python. Mais conciso. Bom quando o erro é uma exceção rara.
duck_typing_seguro.py
# LBYL — Look Before You Leap
# Verifica se o método existe antes de chamar
def finalizar_venda_segura(metodo, total):
    if hasattr(metodo, 'pagar'):
        metodo.pagar(total)
    else:
        print(f"Erro: {type(metodo).__name__} não tem método pagar()")

# EAFP — Easier to Ask Forgiveness than Permission
# Tenta executar e trata o erro se acontecer
def finalizar_venda_pythonica(metodo, total):
    try:
        metodo.pagar(total)
    except AttributeError:
        print(f"Erro: {type(metodo).__name__} não sabe pagar()")

comparativo técnico

Herança vs Duck Typing — quando usar cada um

Polimorfismo por Herança

  • 🌳 Objetos têm parentesco lógico real ('Cachorro É UM Animal')
  • 🌳 Você quer garantir que todos tenham o método
  • 🌳 Sistemas grandes com equipes diferentes
  • 🌳 Ex: Animal, Veículo, Funcionário

Duck Typing

  • 🦆 Objetos não têm parentesco, mas compartilham comportamento
  • 🦆 Você quer máxima flexibilidade e menos burocracia
  • 🦆 Scripts, automações, sistemas de plugins
  • 🦆 Ex: qualquer coisa que tenha pagar(), enviar(), processar()

polimorfismo que você já usa

Dunder Methods: Python usa polimorfismo o tempo todo

  • 📏 len(lista), len(string), len(dicionário): Funcionam porque todos implementam __len__. Duck Typing nativo do Python.
  • 📝 print(objeto): Funciona em qualquer objeto porque Python chama __str__ — que você já aprendeu a sobrescrever.

O que são Dunder Methods?

Métodos com duplo underscore (__) que integram sua classe ao comportamento nativo do Python. Ao implementar __len__, sua classe passa a ser compatível com len() — sem herdar nada.

dunder methods na prática

Fazendo sua classe falar Python nativo

Ao implementar __len__, sua classe passa a responder à função nativa len() — exatamente como listas e strings.

🔌
Você não criou um método tamanho() ou quantidade(). Você fez sua classe falar a língua nativa do Python.
🧩
Isso é Duck Typing em nível de linguagem: len() funciona em tudo que tem __len__ — lista, string, dicionário, e agora Turma.
dunder_len.py
class Turma:
    def __init__(self, alunos):
        self.alunos = alunos

    def __len__(self):
        return len(self.alunos)

    def __str__(self):
        return f"Turma com {len(self)} alunos"

aula = Turma(['Ana', 'Bruno', 'Carla', 'Diego'])

print(len(aula))   # 4  — Python chamou __len__ internamente
print(aula)        # Turma com 4 alunos  — Python chamou __str__

conhecendo antes de evitar

O que é isinstance()?

É uma função nativa do Python que verifica se um objeto pertence a uma determinada classe. Parece útil — e às vezes é. Mas tem uma armadilha.

📌
isinstance(obj, Classe) retorna True ou False. Útil para validar entrada de dados.
🚨
Quando usado para decidir o que fazer com o objeto, vira o mesmo problema do if/elif de tipo que vimos no início da aula.
isinstance_exemplo.py
class Cachorro:
    def falar(self):
        print("Au!")

class Gato:
    def falar(self):
        print("Miau!")

dog = Cachorro()

# isinstance() pergunta: 'esse objeto é dessa classe?'
print(isinstance(dog, Cachorro))  # True
print(isinstance(dog, Gato))      # False

# O problema: usar isso para decidir o que fazer
def fazer_falar(animal):
    if isinstance(animal, Cachorro):
        animal.falar()
    elif isinstance(animal, Gato):
        animal.falar()
    # novo animal? precisa abrir aqui e adicionar mais um elif

boas práticas

O sinal de alerta: isinstance() dentro de lógica

  • 🚫 O problema: isinstance(obj, Cachorro) pergunta 'quem você é?'. Polimorfismo não pergunta — só manda agir.
  • A solução: Mova a lógica condicional para dentro de cada classe. Chame obj.agir() e deixe cada objeto saber o que 'agir' significa.

Onde isinstance() é válido

Validação de entrada de dados (verificar se o usuário passou o tipo certo), debugging e logging de erros. O problema é quando isinstance() substitui polimorfismo em lógica de negócio.

resumo de conceitos

Glossário da Aula 09

item detalhe
Polimorfismo Mesma chamada de método em objetos diferentes — cada um responde com sua própria implementação.
Interface Comum O nome do método que todos os objetos compartilham. É o 'contrato' informal que permite o polimorfismo.
Duck Typing Estilo Python: não importa a classe do objeto, importa se ele tem o método que você precisa.
Dunder Method Método com __ duplo que integra sua classe ao comportamento nativo Python (len, str, comparações etc).
Late Binding Python decide qual método chamar no momento da execução — por isso listas heterogêneas funcionam.
EAFP Easier to Ask Forgiveness than Permission — estilo Pythonico de tentar e tratar o erro, em vez de verificar antes.

laboratório em sala · duplas

Exercício ao Vivo: Sistema de Notificações

Em duplas. 20 minutos. O objetivo é implementar um sistema de notificações usando Duck Typing — sem herança obrigatória.

1

Crie os canais

Classes Email, SMS e PushNotification. Cada uma com método enviar(msg) que imprime uma mensagem diferente.

2

Crie o disparador

Função alerta_geral(canais, mensagem) que percorre a lista e chama enviar() em cada canal. Sem if. Sem isinstance.

3

Adicione resiliência

Coloque um try/except AttributeError no disparador para que um canal sem enviar() não quebre o sistema — apenas pule e avise.

4

Teste com objeto inválido

Adicione um objeto qualquer na lista (ex: um número inteiro) e confirme que o sistema sobrevive sem travar.

resolução · laboratório em sala

Passo 1 — Criando os três canais

  • 📧 Email: imprime a mensagem formatada como e-mail com remetente fictício.
  • 📱 SMS: imprime com limite de caracteres simulado e prefixo de operadora.
  • 🔔 PushNotification: imprime como notificação de app com emoji de alerta.

O que importa neste passo

As três classes não têm nenhum parentesco entre si. O único ponto em comum é o nome do método: enviar(msg). Isso é suficiente para o Duck Typing funcionar.

resolução · passo 1

Código: Os Três Canais

Classes independentes, mesmo método, saídas diferentes.

Três classes. Zero herança. Cada uma sabe o que 'enviar' significa para ela.
📌
O SMS já tem lógica própria (limite de 50 chars) — exatamente o ponto do polimorfismo: cada um resolve do seu jeito.
notificacoes_canais.py
class Email:
    def enviar(self, msg):
        print(f"📧 [EMAIL] De: sistema@app.com")
        print(f"         Mensagem: {msg}")

class SMS:
    def enviar(self, msg):
        resumo = msg[:50] + '...' if len(msg) > 50 else msg
        print(f"📱 [SMS] {resumo}")

class PushNotification:
    def enviar(self, msg):
        print(f"🔔 [PUSH] ⚠️ Alerta: {msg}")

resolução · passo 2

Código: O Disparador e o Teste Inicial

A função alerta_geral não sabe — e não precisa saber — qual tipo de canal está recebendo.

🔄
O loop trata todos os canais da mesma forma. Cada objeto sabe o que fazer quando enviar() é chamado.
Quer adicionar WhatsApp? Crie a classe com enviar() e adicione na lista. Zero mudança na função.
notificacoes_disparador.py
def alerta_geral(canais, mensagem):
    print(f"--- Disparando alerta para {len(canais)} canal(is) ---")
    for canal in canais:
        canal.enviar(mensagem)  # Duck Typing puro — sem if, sem isinstance
    print("--- Fim do disparo ---")

canais = [
    Email(),
    SMS(),
    PushNotification(),
    Email(),
]

alerta_geral(canais, "Servidor em manutenção às 23h")

resolução · passo 3 e 4

Código: Resiliência e Teste com Objeto Inválido

Adicionando try/except para que um canal quebrado não derrube o sistema inteiro.

🛡️
O try/except AttributeError captura qualquer objeto que não tenha enviar() e segue para o próximo.
🔥
O sistema não trava. Um canal inválido gera um aviso e o disparo continua para os demais.
notificacoes_final.py
def alerta_geral(canais, mensagem):
    print(f"--- Disparando alerta para {len(canais)} canal(is) ---")
    for canal in canais:
        try:
            canal.enviar(mensagem)
        except AttributeError:
            nome = type(canal).__name__
            print(f"⚠️  [{nome}] ignorado — não implementa enviar()")
    print("--- Fim do disparo ---")

canais = [
    Email(),
    SMS(),
    42,                 # ← vai falhar
    PushNotification(),
    "texto qualquer",  # ← também vai falhar
]

alerta_geral(canais, "Teste de resiliência")

resolução · saída esperada

Saída Completa do Programa

O que o terminal exibe ao rodar o código final com os objetos inválidos na lista.

Email, SMS e PushNotification executaram normalmente via Duck Typing.
int e str foram capturados pelo except — o sistema sobreviveu sem travar.
saida_esperada.txt
--- Disparando alerta para 5 canal(is) ---
📧 [EMAIL] De: sistema@app.com
         Mensagem: Teste de resiliência
📱 [SMS] Teste de resiliência
⚠️  [int] ignorado — não implementa enviar()
🔔 [PUSH] ⚠️ Alerta: Teste de resiliência
⚠️  [str] ignorado — não implementa enviar()
--- Fim do disparo ---

encerramento

O que dominamos hoje

  • O problema: Código sem polimorfismo cresce com if/elif e se torna frágil.
  • O conceito: Mesma ordem para objetos diferentes — cada um responde do seu jeito.
  • Por herança: Classe pai define o método, filhas entregam sua versão.
  • Duck Typing: Sem herança obrigatória — basta ter o método.
  • Dunder methods: Sua classe integrada ao comportamento nativo do Python.
  • Segurança: hasattr() e try/except para Duck Typing em produção.

exercícios para casa · visão geral

Desafios de Implementação

Do fácil ao expert — construindo polimorfismo camada por camada.

01–02

Nível Fácil

Interface comum em classes simples.

03–04

Nível Médio

Listas heterogêneas e Dunder Methods.

05

Nível Difícil

Sistema de plugins via Duck Typing.

06

Nível Expert

Refatorar if/elif para polimorfismo.

exercícios · fácil

Fácil: Interface Comum

01

Simulador de Sons

Use herança. Crie a classe pai Instrumento com o método tocar(). Depois crie Piano, Violao e Bateria herdando dela — cada uma sobrescreve tocar() com seu próprio som. Percorra uma lista com os três chamando tocar() em cada um.

02

Meios de Transporte

Use Duck Typing — sem herança, sem classe pai. Crie Carro, Aviao e Barco diretamente, cada um com o método mover() imprimindo como se locomove. Percorra uma lista com os três chamando mover().

exercícios · médio

Médio: Pythonic Way

03

Calculadora de Áreas

Use herança. Crie a classe pai Forma com o método area(). Depois crie Circulo(raio), Retangulo(base, altura) e Triangulo(base, altura) herdando dela — cada uma implementa area() com sua fórmula. Por fim, crie a função calcular_area_total(lista) que percorre a lista e soma todas as áreas sem nenhum if.

04

Objeto Medível com __len__

Crie a classe Playlist(nome, musicas) onde musicas é uma lista de strings. Implemente __len__ para que len(playlist) retorne a quantidade de músicas, e __str__ para que print(playlist) exiba algo como Playlist 'Rock Clássico' — 5 músicas.

exercícios · difícil e expert

Avançado: Arquitetura

05

Sistema de Exportação

Use Duck Typing puro — sem herança. Crie PDFExporter e CSVExporter, cada um com o método exportar(dados) que imprime os dados formatados do seu jeito. Crie a função exportar_relatorio(exporter, dados) que chama exportar() sem saber qual classe está recebendo. Bônus: adicione um try/except AttributeError para o caso de receber um objeto inválido.

06

Refatoração Mestre

Refatore o código abaixo para polimorfismo — cada classe Usuario deve implementar acessar() com sua própria lógica, eliminando todos os if/elif:

def liberar_acesso(usuario, tipo):
  if tipo == 'admin':
    print('Acesso total')
  elif tipo == 'editor':
    print('Acesso a conteúdo')
  elif tipo == 'cliente':
    print('Acesso básico')

revisão final

Resumo da Aula 09 — O essencial

  • Polimorfismo = mesma ordem, reações diferentes.
  • O loop não sabe — e não precisa saber — qual objeto está chamando.
  • Por herança: contrato via hierarquia. Duck Typing: sem hierarquia, só comportamento.
  • Dunder methods fazem sua classe falar a língua nativa do Python.
  • isinstance() em lógica de negócio = polimorfismo incompleto.
  • LBYL (hasattr) e EAFP (try/except) são as duas ferramentas de segurança do Duck Typing — cada uma com seu momento certo.
próxima aula

Aula 10 · 15/05

Classes Abstratas e Interfaces

Lembra do return 0 na classe Forma? Na próxima aula vamos resolver isso de vez com Classes Abstratas — forçando que toda subclasse implemente os métodos necessários.

ABC Module Abstract Methods Formal Interfaces Enforcing Contracts