0%
Programação Orientada a Objetos em Python

POO

Estruture seu código com objetos e classes

10-15 min

Programação Orientada a Objetos em Python

A Programação Orientada a Objetos (POO) é um paradigma de programação que organiza o código em torno de objetos, em vez de funções e lógica. Python, por ser uma linguagem multiparadigma, oferece suporte completo e elegante à POO. Neste tutorial, vamos explorar os conceitos fundamentais da POO em Python e entender como utilizá-los de forma eficiente em seus programas.

Por que usar a POO?

Antes de mergulhar nos detalhes, é importante entender por que a POO é tão popular:

  1. Organização: a POO permite organizar seu código de maneira mais estruturada e modular.
  2. Reutilização: ela facilita a reutilização de código graças à herança e à composição.
  3. Manutenibilidade: um código bem estruturado em objetos geralmente é mais fácil de manter e evoluir.
  4. Encapsulamento: a POO permite esconder a complexidade e proteger os dados por meio do encapsulamento.

Classes e objetos

Os dois conceitos fundamentais da POO são as classes e os objetos.

Classes

Uma classe é um modelo ou uma planta para criar objetos. Ela define os atributos (variáveis) e os métodos (funções) que os objetos terão.

Veja como definir uma classe simples em Python:

class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age
    
    def saluer(self):
        return f"Bonjour, je m'appelle {self.nom} et j'ai {self.age} ans."

Neste exemplo:

  • Personne é o nome da classe.
  • __init__ é um método especial (construtor) que inicializa um novo objeto.
  • self faz referência à instância do objeto atual.
  • nom e age são atributos.
  • saluer é um método.

Objetos

Um objeto é uma instância de uma classe. Para criar um objeto, você chama a classe como se fosse uma função:

personne1 = Personne("Alice", 30)
personne2 = Personne("Bob", 25)

print(personne1.saluer())  # Exibe: Bonjour, je m'appelle Alice et j'ai 30 ans.
print(personne2.saluer())  # Exibe: Bonjour, je m'appelle Bob et j'ai 25 ans.

Os objetos personne1 e personne2 são instâncias distintas da classe Personne, cada uma com seus próprios valores de atributos.

Métodos especiais

Python oferece vários métodos especiais (também chamados de métodos mágicos ou métodos dunder, de “double underscore”) que permitem personalizar o comportamento dos objetos.

class Livre:
    def __init__(self, titre, auteur, pages):
        self.titre = titre
        self.auteur = auteur
        self.pages = pages
        self.page_actuelle = 0
    
    def __str__(self):
        """Définit comment l'objet est représenté sous forme de chaîne."""
        return f"{self.titre} par {self.auteur}"
    
    def __len__(self):
        """Définit le comportement quand la fonction len() est appliquée à l'objet."""
        return self.pages
    
    def __del__(self):
        """Méthode appelée lorsque l'objet est supprimé."""
        print(f"Le livre {self.titre} a été fermé.")

livre = Livre("Python Facile", "J. Dupont", 200)
print(livre)           # Utilise __str__
print(len(livre))      # Utilise __len__
del livre              # Déclenche __del__

Herança

A herança permite que uma classe herde os atributos e métodos de outra classe. É um conceito fundamental para promover a reutilização de código.

class Animal:
    def __init__(self, nom):
        self.nom = nom
    
    def parler(self):
        pass  # Método a ser sobrescrito nas classes derivadas

class Chien(Animal):
    def parler(self):
        return f"{self.nom} dit Woof!"

class Chat(Animal):
    def parler(self):
        return f"{self.nom} dit Meow!"

animaux = [Chien("Rex"), Chat("Misty")]
for animal in animaux:
    print(animal.parler())

Neste exemplo:

  • Animal é a classe base (ou classe pai).
  • Chien e Chat são classes derivadas (ou classes filhas) que herdam de Animal.
  • O método parler é sobrescrito (redefinido) em cada classe derivada.

Herança múltipla

Ao contrário de algumas linguagens de programação, Python suporta herança múltipla, o que permite que uma classe herde de várias classes pai.

class A:
    def methode_a(self):
        return "Méthode de A"

class B:
    def methode_b(self):
        return "Méthode de B"

class C(A, B):  # Herda de A e B
    def methode_c(self):
        return "Méthode de C"

objet = C()
print(objet.methode_a())  # Herdado de A
print(objet.methode_b())  # Herdado de B
print(objet.methode_c())  # Definido em C

Encapsulamento

O encapsulamento é o conceito de agrupar os dados e os métodos que operam sobre esses dados, restringindo o acesso direto às variáveis de um objeto.

Em Python, o encapsulamento é obtido por convenção, e não por aplicação estrita:

class CompteBancaire:
    def __init__(self, solde_initial):
        self._solde = solde_initial  # Convenção: atributo protegido (single underscore)
        self.__compte_id = "123456"  # Convenção: atributo privado (double underscore)
    
    def deposer(self, montant):
        self._solde += montant
    
    def retirer(self, montant):
        if montant <= self._solde:
            self._solde -= montant
            return True
        return False
    
    def get_solde(self):
        return self._solde

compte = CompteBancaire(1000)
compte.deposer(500)
print(compte.get_solde())  # 1500
print(compte._solde)       # Acessível, mas, por convenção, não deveria ser acessado diretamente
# print(compte.__compte_id)  # Erro: renomeado por "name mangling"
print(compte._CompteBancaire__compte_id)  # Acessível via mangling

Em Python:

  • Um atributo com um único underscore (_solde) indica que ele é protegido (convenção, não imposta).
  • Um atributo com duplo underscore (__compte_id) está sujeito ao “name mangling” (renomeação), o que dificulta o acesso acidental, mas não o torna realmente privado.

Polimorfismo

O polimorfismo permite que objetos de diferentes classes sejam tratados como objetos de uma classe comum. Em Python, o polimorfismo é intrínseco à linguagem graças ao duck typing.

def faire_parler(animal):
    print(animal.parler())

chien = Chien("Rex")
chat = Chat("Misty")

faire_parler(chien)  # Rex dit Woof!
faire_parler(chat)   # Misty dit Meow!

A função faire_parler funciona com qualquer objeto que tenha um método parler, sem se preocupar com sua classe concreta.

Propriedades

As propriedades permitem controlar o acesso aos atributos de uma classe mantendo uma interface limpa.

class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("La température ne peut pas être inférieure au zéro absolu.")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        self.celsius = (value - 32) * 5/9

temp = Temperature()
temp.celsius = 25
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

temp.fahrenheit = 77
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

Métodos e atributos de classe

Ao contrário dos métodos e atributos de instância, que são próprios de cada objeto, os métodos e atributos de classe são compartilhados por todas as instâncias da classe.

class Voiture:
    # Atributo de classe
    nombre_de_voitures = 0
    
    def __init__(self, marque, modele):
        self.marque = marque
        self.modele = modele
        # Incrementar o atributo de classe
        Voiture.nombre_de_voitures += 1
    
    @classmethod
    def get_nombre_de_voitures(cls):
        return cls.nombre_de_voitures
    
    @staticmethod
    def est_electrique(marque, modele):
        # Um método estático que não depende do estado da instância
        # Lista fictícia de carros elétricos
        voitures_electriques = [("Tesla", "Model 3"), ("Nissan", "Leaf")]
        return (marque, modele) in voitures_electriques

voiture1 = Voiture("Toyota", "Corolla")
voiture2 = Voiture("Honda", "Civic")

print(Voiture.get_nombre_de_voitures())  # 2
print(Voiture.est_electrique("Tesla", "Model 3"))  # True

Conclusão

A programação orientada a objetos em Python oferece uma maneira poderosa e flexível de organizar seu código. Ela permite criar programas mais modulares, reutilizáveis e fáceis de manter.

Neste tutorial, cobrimos os conceitos fundamentais da POO em Python, incluindo classes, objetos, herança, polimorfismo e encapsulamento. Mas isso é apenas o começo! Existem muitos outros conceitos avançados e padrões de projeto (design patterns) que podem ajudar você a tirar o máximo proveito da POO.

No próximo tutorial, vamos explorar o tratamento de exceções em Python, um aspecto crucial para escrever programas robustos.

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!