Conteúdos

Callable Python

Introdução

Python tem diversos métodos mágicos que, às vezes, podem ser realmente confusos. Muitas vezes não percebemos a real necessidade de um determinado método, ou não sabemos como aplicá-lo no mundo real.

Nesse post, explicarei uma utilização real de um deles, o famoso __call__.

Classe Abstrata

A linguagem Python tem suporte à classe abstrata Callabe, que nos auxilia na criação de uma classe compatível com o protocolo Callable, criando uma classe que herde de Callable nos auxilia na correta implementação da mesma.

Para utilizar esse classe abstrata basta importá-la da biblioteca abc: from collections.abc import Callabe e herdá-la na sua própria classe.

Utilização

Nesse post, irei exemplificar com a utilização de um Mapper direto de um ORM (no caso, SQLAlchemy), para um objeto, ou classe, de domínio. Ou seja, iremos transformar os campos do ORM, para um objeto Python sem nenhum acoplamento ou dependências externas.

Classe Callable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from .dog_domain import Dog
from collections.abc import Callable


class DogMapper(Callable):
    @staticmethod
    def to_domain(dog):
        return Dog(name=dog.name, legs=dog.legs, color=dog.color,) if dog else None

    def __call__(self, dog):
        return self.to_domain(dog)

Classe ORM de exemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from app import db
from .dog_mapper import DogMapper


class Dog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    legs = db.Column(db.Integer)
    color = db.Column(db.Integer)
    
    @property
    def mapper(self):
        return DogMapper()(self)

Classe de domínio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Dog:
    def __init__(self, name, legs, color):
        self.name = name
        self.legs = legs
        self.color = color

    @clasmethod
    def create(cls, name, color, legs=4):
        return cls(name, color, legs,)

Explicação

Nesse caso, utilizamos a property mapper para realizar a inicialização do mapper, e a conversão para o objeto de domínio automaticamente. O que facilita bastante caso tivéssemos que obter alguma classe por id, depois importar o Mapper e depois realizar a conversão.

Feito dessa forma, o callable é utilizado somente sob demanda, e quando necessário. Assim não realizamos a conversão sem que haja real necessidade.

Assim, podemos utilizar o mapper diretamente do model, logo na sequência, como por exemplo:

1
dog = Dog.query.get(id=15).mapper

Conclusão

Nesse post tentei demonstrar uma utilização real de uma classe Callable, espero que tenha ajudado! Caso tenha alguma dúvida, ou sugestão, não hesite em comentar. 😉

Nos vemos por aí!

Referências