Fundamentos de Python

Programação orientada a objetos em Python

A POO organiza o programa em objetos que possuem estado e oferecem comportamento por interfaces claras.

O que é programação orientada a objetos em Python?

A POO modela um sistema como objetos colaboradores. Cada objeto combina estado e operações válidas, tornando responsabilidades mais claras em aplicações grandes.

Os quatro princípios fundamentais

  • Encapsulamento: reunir estado e comportamento e controlar o acesso.
  • Abstração: expor uma interface útil e ocultar detalhes desnecessários.
  • Herança: especializar uma classe apenas quando existe uma verdadeira relação é-um.
  • Polimorfismo: usar a mesma operação com objetos distintos e comportamento adequado.

Como o exemplo foi projetado

  1. BankAccount possui o saldo e valida depósitos.
  2. SavingsAccount reutiliza o contrato base.
  3. SavingsAccount sobrescreve month_end para aplicar juros.
  4. O laço usa todas as contas pela mesma interface.
Dica: Prefira composição quando um objeto apenas usa outro; use herança somente quando o filho puder substituir corretamente o pai.

Exemplo básico

Executar código →
main.py
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self._balance = float(balance)

    @property
    def balance(self):
        return self._balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Deposit must be positive")
        self._balance += amount

    def month_end(self):
        return "No interest"


class SavingsAccount(BankAccount):
    def __init__(self, owner, balance, interest_rate):
        super().__init__(owner, balance)
        self.interest_rate = interest_rate

    def month_end(self):
        self._balance *= 1 + self.interest_rate
        return "Interest applied"


accounts = [
    BankAccount("Ada", 100),
    SavingsAccount("Lin", 200, 0.05),
]
accounts[0].deposit(50)

for account in accounts:
    status = account.month_end()
    print(f"{account.owner}: {account.balance:.2f} ({status})")

Saída esperada

Ada: 150.00 (No interest)
Lin: 210.00 (Interest applied)

Os quatro princípios de POO na prática

Estes exemplos mostram como Python aplica encapsulamento, abstração, herança e polimorfismo no código cotidiano.

Encapsulamento

Executar código →

reunir estado e comportamento e controlar o acesso.

encapsulation.py
class BankAccount:
    def __init__(self, balance=0):
        # Double underscores prevent accidental direct access.
        self.__balance = balance

    @property
    def balance(self):
        # Expose read access without exposing mutation.
        return self.__balance

    def deposit(self, amount):
        # Keep validation next to the state it protects.
        if amount <= 0:
            raise ValueError("Amount must be positive")
        self.__balance += amount


account = BankAccount(100)
account.deposit(50)
print(account.balance)  # 150

Abstração

Executar código →

expor uma interface útil e ocultar detalhes desnecessários.

abstraction.py
from abc import ABC, abstractmethod


class PaymentMethod(ABC):
    @abstractmethod
    def pay(self, amount):
        # Callers know what pay does, not how each provider does it.
        pass


class CreditCard(PaymentMethod):
    def pay(self, amount):
        # The concrete class hides its payment implementation.
        return f"Paid ${amount:.2f} by card"


payment = CreditCard()
print(payment.pay(25))

Herança

Executar código →

especializar uma classe apenas quando existe uma verdadeira relação é-um.

inheritance.py
class Employee:
    def __init__(self, name):
        self.name = name

    def describe(self):
        return self.name


class Developer(Employee):
    def __init__(self, name, language):
        # Reuse initialization from the parent class.
        super().__init__(name)
        self.language = language

    def describe(self):
        # Extend inherited behavior instead of duplicating it.
        return f"{super().describe()} writes {self.language}"


print(Developer("Ada", "Python").describe())

Polimorfismo

Executar código →

usar a mesma operação com objetos distintos e comportamento adequado.

polymorphism.py
class EmailNotification:
    def send(self, message):
        return f"Email: {message}"


class SmsNotification:
    def send(self, message):
        return f"SMS: {message}"


def notify(channels, message):
    for channel in channels:
        # The same call selects behavior from each concrete object.
        print(channel.send(message))


channels = [EmailNotification(), SmsNotification()]
notify(channels, "Order shipped")

Como funciona

BankAccount encapsula o saldo. SavingsAccount herda a interface e sobrescreve month_end. O laço trata ambos uniformemente e Python seleciona o método em tempo de execução.

Altere os valores e execute o programa no compilador Python online CodeUtility sem instalar Python.

Exercícios práticos

Altere as entradas e teste casos de borda antes de usar conjuntos de dados maiores.

  1. Preveja a saída antes de executar.
  2. Trate entradas vazias ou inválidas.
  3. Extraia a lógica para uma função e adicione testes.
Executar no IDE Python →