Encapsulamento e Herança
Encapsulamento esconde os detalhes internos de um objeto, expondo apenas interfaces operacionais seguras. Herança permite que uma classe tenha automaticamente a funcionalidade de outra, evitando repetição. Estes dois conceitos são a espinha dorsal da programação orientada a objetos.
1. Encapsulamento e Atributos Privados
Encapsulamento significa que os dados internos de um objeto não devem ser acessados diretamente de fora — devem ser manipulados através de métodos.
Sublinhado Simples _ — Convenção para Atributos "Protegidos"
Exemplo: Sublinhado Simples e Duplo
class Pessoa:
def __init__(self, nome, idade):
self.nome = nome
self._idade = idade # Sublinhado simples: dica de que é interno
p = Pessoa("João Silva", 25)
print(p.nome) # João Silva — atributo público
print(p._idade) # 25 — acessível, mas não recomendado
Um sublinhado simples é apenas uma convenção, não imposta — Python não impede você de acessá-lo. É como escrever na documentação "isto é interno, não toque."
Sublinhado Duplo __ — Name Mangling
Exemplo: Classe Conta Bancária
class ContaBancaria:
def __init__(self, titular, saldo):
self.titular = titular
self.__saldo = saldo # Sublinhado duplo: atributo privado
def get_saldo(self):
"""Obtém saldo com segurança"""
return self.__saldo
def depositar(self, valor):
if valor > 0:
self.__saldo += valor
return True
return False
conta = ContaBancaria("João Silva", 10000)
print(conta.titular) # João Silva — público
# print(conta.__saldo) # Erro! AttributeError
print(conta.get_saldo()) # 10000 — acessado via método
Sublinhados duplos acionam name mangling — __saldo é internamente transformado para _ContaBancaria__saldo. Isso não é "privacidade" verdadeira, apenas torna menos provável a sobrescrita acidental.
private verdadeira; Python não tem e não planeja adicionar uma.
Exemplo: Classe Temperatura (Dificuldade ⭐⭐)
class Temperatura:
def __init__(self, celsius=0):
self.__celsius = celsius
def to_fahrenheit(self):
return self.__celsius * 9 / 5 + 32
def set_celsius(self, valor):
"""Define temperatura com segurança — não pode ser abaixo do zero absoluto"""
if valor < -273.15:
print("Temperatura não pode ser abaixo do zero absoluto!")
return
self.__celsius = valor
def get_celsius(self):
return self.__celsius
t = Temperatura(100)
print(f"100°C = {t.to_fahrenheit():.1f}°F") # 212.0°F
t.set_celsius(-300) # Temperatura não pode ser abaixo do zero absoluto!
t.set_celsius(0)
print(f"0°C = {t.to_fahrenheit():.1f}°F") # 32.0°F
2. @property: Controle Elegante de Acesso
Escrever set_celsius() / get_celsius() é verboso. @property permite controlar o acesso mantendo a sintaxe de acesso a atributos:
Exemplo: Usando @property
class Temperatura:
def __init__(self, celsius=0):
self._celsius = celsius
@property
def celsius(self):
"""Obtém temperatura em Celsius"""
return self._celsius
@celsius.setter
def celsius(self, valor):
"""Define temperatura em Celsius — auto-validação"""
if valor < -273.15:
raise ValueError("Temperatura não pode ser abaixo do zero absoluto!")
self._celsius = valor
@property
def fahrenheit(self):
"""Fahrenheit (somente leitura — sem setter)"""
return self._celsius * 9 / 5 + 32
t = Temperatura(100)
print(t.celsius) # 100 — acessado como atributo
print(t.fahrenheit) # 212.0
t.celsius = 0 # Atribuído como atributo
print(t.celsius) # 0
# t.celsius = -300 # Levantaria ValueError!
# t.fahrenheit = 100 # Erro! Sem setter
@property: 1) Sem parênteses para acesso: t.celsius em vez de t.get_celsius(). 2) Validação automática na atribuição: t.celsius = valor em vez de t.set_celsius(valor). 3) Pode converter um atributo regular em um computado sem quebrar código existente.
3. Herança
Herança permite que uma classe filha tenha todos os atributos e métodos de sua classe pai:
Exemplo: Herança Animal
class Animal:
"""Classe base Animal"""
def __init__(self, nome):
self.nome = nome
def falar(self):
return "..."
def comer(self, comida):
return f"{self.nome} está comendo {comida}"
class Cachorro(Animal):
"""Cachorro — herda de Animal"""
def falar(self):
return "Au au!"
class Gato(Animal):
"""Gato — herda de Animal"""
def falar(self):
return "Miau!"
dog = Cachorro("Rex")
cat = Gato("Mimi")
print(dog.falar()) # Au au! (sobrescreve método do pai)
print(cat.falar()) # Miau! (sobrescreve método do pai)
print(dog.comer("osso")) # Rex está comendo osso (herdado do pai)
print(cat.comer("peixe")) # Mimi está comendo peixe (herdado do pai)
super(): Chamando Métodos do Pai
Exemplo: super() para Chamar o Pai
class Animal:
def __init__(self, nome):
self.nome = nome
class Cachorro(Animal):
def __init__(self, nome, raca):
super().__init__(nome) # Chama o __init__ do pai
self.raca = raca # Adiciona atributo específico do filho
def apresentar(self):
return f"Sou {self.nome}, um {self.raca}"
dog = Cachorro("Rex", "Golden Retriever")
print(dog.apresentar()) # Sou Rex, um Golden Retriever
4. Padrão Mixin
Um Mixin é uma classe especial — não usada independentemente, mas "misturada" para adicionar funcionalidade a outras classes:
Exemplo: Padrão Mixin
class MixinVoador:
"""Mixin de habilidade de voo"""
def voar(self):
return f"{self.nome} está voando!"
class MixinNadador:
"""Mixin de habilidade de natação"""
def nadar(self):
return f"{self.nome} está nadando!"
class Animal:
def __init__(self, nome):
self.nome = nome
class Pato(Animal, MixinNadador, MixinVoador):
"""Pato — pode nadar e voar"""
def falar(self):
return "Quack!"
class Peixe(Animal, MixinNadador):
"""Peixe — só pode nadar"""
def falar(self):
return "..."
pato = Pato("Donald")
peixe = Peixe("Nemo")
print(pato.falar()) # Quack!
print(pato.nadar()) # Donald está nadando!
print(pato.voar()) # Donald está voando!
print(peixe.nadar()) # Nemo está nadando!
Mixin indicam que são para misturar, não para uso independente. Uma classe pode misturar múltiplos Mixins mais uma classe base principal — muito mais flexível que herança única profunda.
Casos de Uso Comuns
- Validação de dados: Use
@property.setterpara garantir validade dos dados na atribuição. - Propriedades somente leitura: Use
@propertysem setter para atributos somente leitura. - Reutilização de código: Coloque funcionalidade comum na classe base; subclasses escrevem apenas as diferenças.
- Composição funcional: Use Mixins para adicionar recursos flexivelmente a diferentes classes.
❓ Perguntas Frequentes
P: Quando devo usar herança vs. Mixin? R: Herança é adequada para relacionamentos "é-um" — um cachorro é um animal. Mixins são adequados para "tem a habilidade" — um pato pode nadar. Prefira composição (Mixin) sobre herança, pois hierarquias de herança profundas são difíceis de manter. Uma boa regra: herança não deve exceder 3 níveis. P: Qual a diferença entre
@propertye um método regular? R:@propertyfaz um método parecer um atributo — sem parênteses para acesso, atribuição aciona o setter. É essencialmente um "interceptador de atributos" — você escreve código como se estivesse manipulando um atributo, mas um método realmente executa. P: Python suporta herança múltipla? Alguma armadilha? R: Sim —class C(A, B). No entanto, herança múltipla tem o "problema do diamante" (qual método do pai usar quando ambos têm o mesmo nome). Python usa MRO (Method Resolution Order), pesquisando da esquerda para a direita. Mixins são um padrão de design que aproveita a herança múltipla, com classes Mixin sendo pequenas e funcionalmente independentes, evitando problemas de diamante.
📖 Resumo
- Encapsulamento:
_significa "não toque";__aciona name mangling;@propertyfornece controle elegante de acesso - Herança: classes filhas têm automaticamente atributos e métodos do pai;
super()chama métodos do pai - Sobrescrita de método: classe filha redefine um método com o mesmo nome do pai
- Mixin: use herança múltipla para adicionar funcionalidade flexivelmente; preferível a herança profunda
- Python não tem atributos verdadeiramente privados — baseia-se em convenção e name mangling
📝 Atividades
-
Iniciante (Dificuldade ⭐): Defina uma classe
Produtocom@propertypara o atributopreco— deve ser positivo ao definir; retorna o valor original ao obter. -
Intermediário (Dificuldade ⭐⭐): Defina uma herança de três níveis:
Animal->Mamifero->Cachorro/Gato.Animaltemnomeeidade;Mamiferoadicionacor_pelo;CachorroeGatoimplementam seus próprios métodosfalar(). -
Avançado (Dificuldade ⭐⭐⭐): Crie um sistema de logging com
MixinLogavel(fornece métodoslog_info(),log_error()) e uma classe baseAplicacao(tem um atributonome). FaçaWebAppeCLIAppherdarem deAplicacaoe misturaremMixinLogavelpara implementar funcionalidade de logging.



