Orientação a Objeto com Python

0 – Python
5 – Orientada a Objetos (POO)
5.1 – Classes e objetos
5.2 – Herança (simples e múltipla)
5.3 – Polimorfismo
5.4 – Encapsulamento (público, _protegido, __privado)
5.5 – Métodos mágicos (__init__, __call__, __add__, etc.)
5.6 – Propriedades (@property, setter, deleter)
5.7 – Classes abstratas (ABC, abstractmethod)
5.8 – Metaclasses (type, __new__)
LEGENDA
Nivel_1
Nivel_2
Nivel_3

A orientação a objetos (OO) é um paradigma de programação amplamente usado. Em Python, tudo é tratado como objeto, desde números até funções. Portanto, dominar a OO torna seu código mais modular e reutilizável. Primeiramente, entenda que classes são “fábricas” de objetos. Já os objetos representam entidades do mundo real com atributos e comportamentos. Por exemplo, uma classe Cachorro pode ter o método latir(). Assim, a OO organiza o software de forma mais intuitiva e escalável. Muitos projetos de médio porte são beneficiados por essa abordagem. Ademais, Python oferece suporte nativo e elegante aos quatro pilares da OO. Vamos explorar cada um deles a seguir.

Classes e objetos: a base estrutural

Uma classe é como um molde ou projeto para criar instâncias. Objetos são as instâncias concretas que ocupam memória. Geralmente, usamos classes quando precisamos de múltiplos itens similares. Por exemplo, em um sistema bancário, cada conta é um objeto. A classe ContaBancaria define atributos como saldo e titular. Métodos como depositar(valor) representam ações possíveis. É recomendado criar classes sempre que houver dados e comportamentos fortemente acoplados. Além disso, objetos isolam o estado interno do resto do programa. Isso reduz efeitos colaterais indesejados em sistemas complexos. A sintaxe em Python usa class Nome: e o método __init__ como construtor. O self explicita a referência ao próprio objeto. Muitas linguagens ocultam esse detalhe, mas Python o torna explícito. Assim, iniciantes estranham, mas intermediários apreciam a clareza. Veja um exemplo simples:

No código acima, a classe Pessoa é reutilizável para várias pessoas. Cada objeto tem seu próprio nome e idade. Isso é muito útil em listas de usuários ou cadastros.

Encapsulamento e propriedades

Encapsulamento esconde detalhes internos de implementação. Em Python, usamos convenção de nomes com sublinhado (_atributo) para indicar proteção. Atributos privados de verdade usam dois sublinhados (__atributo), causando name mangling. Isso é feito para evitar acesso acidental fora da classe. Quando devemos usar encapsulamento? Sempre que um atributo não deve ser alterado livremente. Por exemplo, um saldo bancário só pode mudar via métodos sacar ou depositar. Propriedades com @property permitem controle sobre leitura e escrita. Elas são frequentemente usadas para validação de dados. Caso contrário, o usuário da classe poderia corromper seu estado interno. A voz passiva é empregada aqui: “o acesso é bloqueado por convenção”. Transições como “por exemplo” e “além disso” ajudam a fluir a explicação. Foi dito anteriormente que Python confia no programador, mas oferece ferramentas. Então, use encapsulamento para interfaces claras e seguras. Um bom indicador: se um atributo pode ficar inconsistente, proteja-o. Veja a aplicação prática:

Herança e polimorfismo

Herança permite criar uma classe filha a partir de uma classe mãe. A classe filha reaproveita métodos e atributos da mãe. Isso é útil quando há uma relação “é um” entre os conceitos. Por exemplo, Caminhao e Carro herdam de Veiculo. Assim, evitamos duplicação de código para comportamentos comuns. O polimorfismo vem em seguida: objetos de diferentes classes respondem à mesma mensagem. Em Python, isso é natural com duck typing. Mas a herança formal com métodos sobrescritos também é suportada. Sobrescrever um método significa redefinir seu comportamento na classe filha. Isso é feito com a mesma assinatura do método original. Geralmente, a herança é aplicada quando há especialização genuína. Caso contrário, prefira composição (ter um objeto dentro de outro). Foi observado que herança em excesso gera hierarquias frágeis. Portanto, use-a com moderação e apenas para is-a relationships. Polimorfismo permite escrever funções genéricas como fazer_som(animal). Cada animal (cachorro, gato) emite seu próprio som. Isso é poderoso para código flexível e extensível. Veja um exemplo clássico:

Nesse código, a função emitir_som não precisa saber o tipo exato. Ela confia que qualquer Animal tem um método som. Isso é polimorfismo por subtipagem. Quando usar? Em sistemas que precisam tratar famílias de objetos uniformemente. Por exemplo, editores gráficos com formas (círculo, retângulo) e método desenhar(). Por fim, lembre-se: a orientação a objetos não é a única solução. Contudo, para domínios ricos em entidades e regras de negócio, ela brilha. Python torna tudo isso simples, direto e pragmático. Aplique esses conceitos em seu próximo projeto!

Deixe um comentário