Em desenvolvimento de software, a estruturação de informações segue um processo sistemático. Inicialmente, definimos uma estrutura abstrata denominada classe, que serve como modelo para entidades do domínio. Em seguida, ao instanciar essa classe, criamos um objeto concreto na memória. Por último, preenchemos as características específicas desse objeto através de atribuição de propriedades.
Definição de Métodos de Instância
A sintaxe para declarar métodos em classes é similar à definição de funções convencionais, com uma distinção crucial: a presença do parâmetro especial self. Esse parâmetro é obrigatório em todos os métodos de classe e referencia a própria instância que está executando o método. Quando um método é invocado por um objeto, o interpretador Python automaticamente passa a instância como primeiro argumento para self. Para acessar atributos ou outros métodos da mesma instância dentro do corpo do método, a utilização de self é indispensável. Vale notar que, durante a chamada do método, o argumento correspondente a self não é explicitamente fornecido pelo desenvolvedor.
Método Construtor
As classes em Python podem implementar um método especial chamado __init__, conhecido como construtor. Esse método é executado automaticamente no momento da instanciação da classe, permitindo a inicialização de atriubtos e a realização de configurações iniciais. Os argumentos fornecidos durante a criação do objeto são encaminhados diretamente para os parâmetros do método __init__.
Métodos Especiais (Mágicos)
Python oferece diversos métodos especiais que permitem customizar o comportamento dos objetos em operações específicas. Por exemplo, o método __str__ controla a representação textual de um objeto, similar ao método toString() em Java. Para comparações, podemos implementar métodos como __lt__ (para operadores de menor que) e __eq__ (para igualdade). Esses métodos são invocados implicitamente ao utilizar os operadores correspondentes.
class Produto:
def __init__(self, codigo: int, descricao: str):
self.codigo = codigo
self.descricao = descricao
def __str__(self) -> str:
return f"Produto[{self.codigo}] - {self.descricao}"
def __eq__(self, outro) -> bool:
if isinstance(outro, Produto):
return self.codigo == outro.codigo
return False
Encapsulamento
O encapsulamento é implementado através de membros privados. Para definir um atributo como privado, utiliza-se um prefixo de dois sublinhados no nome da variável (ex: __saldo). Da mesma forma, métodos privados seguem a mesma convenção de nomenclatura. Membros privados não podem ser acessados diretamente fora da classe, mas estão disponíveis para outros métodos internos da mesma classe.
Herança
A herança permite que uma classe filha reutilize atributos e métodos de uma classe pai, promovendo a reutilização de código. Na herança simples, uma classe deriva de uma única superclasse. Na herança múltipla, uma classe pode ter diversas classes pai, com resolução de conflitos de nomes seguindo a ordem de declaração (da esquerda para a direita).
Quando uma classe filha deseja alterar o comportamento herdado, ela pode sobrescrever (override) métodos ou atributos. Para acessar a implementação original da classe pai, utiliza-se a sintaxe super() ou referencia-se diretamente o nome da classe pai.
class Veiculo:
def __init__(self, marca: str):
self.marca = marca
def exibir_info(self):
print(f"Veículo da marca {self.marca}")
class Carro(Veiculo):
def __init__(self, marca: str, modelo: str):
super().__init__(marca)
self.modelo = modelo
def exibir_info(self): # Sobrescrita do método
print(f"Carro {self.marca} modelo {self.modelo}")
meu_carro = Carro("Toyota", "Corolla")
meu_carro.exibir_info() # Saída: Carro Toyota modelo Corolla
Anotações de Tipo
As anotações de tipo em Python são indicadores opcionais que auxiliam no desenvolvimento, fornecendo dicas sobre os tipos de dados esperados para variáveis, parâmetros e valores de retorno. Ferramentas de IDE utilizam essas anotações para melhorar a autocompletação e a detecção de erros. É importante notar que as anotações não impõem verificações em tempo de execução; elas servem apenas como documentação e suporte estático.
def calcular_desconto(preco: float, porcentagem: float) -> float:
return preco * (1 - porcentagem / 100)
# Uso de Union para tipos múltiplos
from typing import Union
def processar_entrada(dado: Union[int, str]) -> str:
return str(dado)
Polimorfismo
O polimorfismo permite que diferentes classes implementem métodos com a mesma interface, resultando em comportamentos variados. Uma abordagem comum é definir uma classe abstrata com métodos sem implementação (métodos abstratos), que servem como contrato para as subclasses. Em Python, isso pode ser simulado utilizando a biblioteca abc.
from abc import ABC, abstractmethod
class Forma(ABC):
@abstractmethod
def area(self) -> float:
pass
class Circulo(Forma):
def __init__(self, raio: float):
self.raio = raio
def area(self) -> float:
return 3.14159 * self.raio ** 2
class Retangulo(Forma):
def __init__(self, largura: float, altura: float):
self.largura = largura
self.altura = altura
def area(self) -> float:
return self.largura * self.altura
def calcular_area_total(formas: list[Forma]) -> float:
total = 0.0
for forma in formas:
total += forma.area()
return total