Da trilha de Python Este conceito ainda não saiu como card do dia. ir para o card de hoje

Python POO Intermediário

Métodos especiais

Em Python, os métodos especiais (ou dunder methods, de double underscore) permitem que objetos de classes personalizadas se comportem como tipos nativos. Eles são chamados automaticamente pelo interpretador em situações específicas, como ao imprimir um objeto (__str__, __repr__), comparar (__eq__), calcular hash (__hash__), obter comprimento (__len__), iterar (__iter__) ou usar operadores (__add__, __sub__, etc.).

Implementar esses métodos torna suas classes mais expressivas e integradas à linguagem. Por exemplo, ao definir __eq__, você pode comparar objetos com ==; com __hash__, eles podem ser usados como chaves de dicionário ou em conjuntos; com __len__, a função len() funciona; e com __iter__, você pode percorrer o objeto em um for.

Neste card, vamos explorar os métodos especiais mais comuns e mostrar como eles permitem que suas classes se comportem como coleções, números ou qualquer outra abstração que você imaginar. O segredo é lembrar que eles nunca são chamados diretamente (exceto em casos raros), mas sim pelo interpretador quando você usa a sintaxe correspondente.

Pontos-chave

  • __repr__ fornece uma representação oficial e não ambígua do objeto, usada em debugging; __str__ é a versão amigável para usuários.
  • __eq__ define igualdade personalizada; se implementado, __hash__ deve ser consistente para permitir uso em sets e dicionários.
  • __len__ e __iter__ permitem que objetos se comportem como coleções, suportando len() e iteração.
  • Operadores como +, -, * podem ser implementados com __add__, __sub__, __mul__, etc., possibilitando aritmética personalizada.
  • Métodos especiais são chamados implicitamente pelo interpretador; não os invoque diretamente a menos que saiba o que está fazendo.
metodos_especiais.py
class Vetor:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f'Vetor({self.x}, {self.y})'

    def __str__(self):
        return f'({self.x}, {self.y})'

    def __eq__(self, other):
        if not isinstance(other, Vetor):
            return NotImplemented
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

    def __add__(self, other):
        if not isinstance(other, Vetor):
            return NotImplemented
        return Vetor(self.x + other.x, self.y + other.y)

    def __len__(self):
        return 2  # um vetor tem duas coordenadas

    def __iter__(self):
        yield self.x
        yield self.y


v1 = Vetor(1, 2)
v2 = Vetor(3, 4)
print(repr(v1))          # Vetor(1, 2)
print(str(v1))           # (1, 2)
print(v1 == Vetor(1, 2)) # True
print(len(v1))           # 2
print(list(v1))          # [1, 2]
print(v1 + v2)           # Vetor(4, 6)
print(hash(v1) == hash(Vetor(1, 2)))  # True

Exercícios

  1. 1
    Fácil

    Representação de uma Pessoa

    Crie uma classe Pessoa com atributos nome e idade. Implemente __repr__ para retornar uma string no formato Pessoa(nome='Alice', idade=30) e __str__ para retornar Alice (30 anos). Teste com uma instância e imprima tanto repr() quanto str().

    Resolver
  2. 2
    Médio

    Igualdade e Hash para Ponto

    Implemente uma classe Ponto que representa um ponto no plano cartesiano com coordenadas x e y. Defina __eq__ para que dois pontos sejam iguais se tiverem as mesmas coordenadas, e __hash__ consistente. Depois, crie um conjunto com alguns pontos e verifique se um ponto duplicado é reconhecido como já existente.

    Resolver
  3. 3
    Desafio

    Lista Personalizada com Operadores

    Crie uma classe MinhaLista que encapsula uma lista de números. Implemente __len__ para retornar o tamanho, __iter__ para permitir iteração, __add__ para concatenar duas listas (retornando uma nova MinhaLista), __getitem__ para acessar elementos por índice e __repr__ para representação. Teste com operações de len(), iteração, concatenação e acesso por índice.

    Resolver

Continue estudando