Pular para o conteúdo

Métodos mágicos

Os 95 ganchos que a linguagem procura no seu blueprint.

Um método mágico é um gancho: a linguagem o procura no blueprint quando uma operação acontece sobre uma instância. Declarar __add__ faz o + funcionar; declarar __getitem__ faz o [] funcionar. São 95, em 16 grupos.

dataforge
blueprint Vetor:
    action setup(x, y):
        self.x := x
        self.y := y

    action __add__(outro):
        yield spawn Vetor(self.x + outro.x, self.y + outro.y)

    action __str__():
        yield $"({self.x}, {self.y})"

    action __eq__(outro):
        yield self.x is outro.x and self.y is outro.y

    action __len__():
        yield 2

out spawn Vetor(1, 2) + spawn Vetor(3, 4)      // imprime (4, 6)
assert len(spawn Vetor(1, 2)) is 2

Por que o nome com dois sublinhados#

Porque é o que quem chega do Python já conhece, e porque o sublinhado duplo sinaliza isto não é para você chamar: ele é chamado pela linguagem, no momento da operação. v.__add__(outro) funciona, mas escrever isso é o mesmo que escrever v + outro de um jeito pior.

Um decorador que devolve void não substitui o alvo#

Vale lembrar aqui porque é a regra que permite @Rota("/x") apenas anotar: se um decorador devolvesse void e isso virasse o novo valor, a ação decorada sumiria.

Construção (6)#

Nascer, morrer e copiar.

MétodoParâmetrosChamado por
__init__0roda no spawn; sinonimo de 'setup'
__new__0cria a instancia antes de '__init__'
__del__0roda quando o objeto e descartado
__copy__0copia rasa
__deepcopy__0copia profunda
__clone__0copia, no vocabulario do DataForge

Texto (5)#

O que out, str() e a interpolação chamam.

MétodoParâmetrosChamado por
__str__0o texto que 'out' imprime
__repr__0o texto para quem depura
__format__1formatacao com especificador
__bytes__0a representacao em bytes
__doc__0a documentacao do objeto

Comparação (7)#

is, isnt, <, <=, >, >= e a ordenação.

MétodoParâmetrosChamado por
__eq__1a == b (e 'a is b')
__ne__1a != b (e 'a isnt b')
__lt__1a < b (e 'a smaller b')
__le__1a <= b
__gt__1a > b (e 'a bigger b')
__ge__1a >= b
__cmp__1-1, 0 ou 1; cobre os seis de uma vez

Aritmética (9)#

+ - * / ~/ % **.

MétodoParâmetrosChamado por
__add__1a + b
__sub__1a - b
__mul__1a * b
__truediv__1a / b
__floordiv__1a ~/ b
__mod__1a % b
__pow__1a ** b
__divmod__1quociente e resto de uma vez
__matmul__1a @ b — multiplicacao de matriz

Aritmética refletida (8)#

Quando o objeto está à direita do operador.

MétodoParâmetrosChamado por
__radd__1b + a, quando 'b' nao sabe somar
__rsub__1b - a
__rmul__1b * a
__rtruediv__1b / a
__rfloordiv__1b ~/ a
__rmod__1b % a
__rpow__1b ** a
__rmatmul__1b @ a

Aritmética no lugar (7)#

+=, -= e as outras compostas.

MétodoParâmetrosChamado por
__iadd__1a += b, alterando 'a'
__isub__1a -= b
__imul__1a *= b
__itruediv__1a /= b
__ifloordiv__1a ~/= b
__imod__1a %= b
__ipow__1a **= b

Unários (8)#

-x, +x, abs(x), round(x).

MétodoParâmetrosChamado por
__neg__0-a
__pos__0+a
__abs__0abs(a)
__invert__0~a
__round__1round(a, casas)
__floor__0floor(a)
__ceil__0ceil(a)
__trunc__0trunc(a)

Bits (8)#

& | ^ ~ << >>.

MétodoParâmetrosChamado por
__and__1a & b
__or__1a | b
__xor__1a ^ b
__lshift__1a << b
__rshift__1a >> b
__rand__1b & a
__ror__1b | a
__rxor__1b ^ a

Conversão (6)#

int(), float(), bool(), len(), hash().

MétodoParâmetrosChamado por
__bool__0o que 'given obj:' decide
__int__0int(obj)
__float__0float(obj)
__complex__0complex(obj)
__index__0o objeto como indice de colecao
__hash__0a chave de vault que este objeto vira

Coleção (10)#

[], in, percurso e tamanho.

MétodoParâmetrosChamado por
__len__0len(obj)
__getitem__1obj[chave]
__setitem__2obj[chave] := valor
__delitem__1delete obj[chave]
__contains__1item in obj
__iter__0'cycle x in obj'
__next__0o proximo item do percurso
__reversed__0percurso de tras para frente
__missing__1chave ausente, antes de dar erro
__length_hint__0tamanho aproximado, para alocar antes

Chamada (1)#

Fazer a instância ser chamável.

MétodoParâmetrosChamado por
__call__-1obj(argumentos)

Atributo (5)#

Ler, escrever e remover campo.

MétodoParâmetrosChamado por
__getattr__1obj.campo, quando o campo nao existe
__getattribute__1obj.campo, SEMPRE
__setattr__2obj.campo := valor
__delattr__1delete obj.campo
__dir__0a lista de nomes do objeto

Descritor (4)#

Um campo cujo acesso é controlado por outro objeto.

MétodoParâmetrosChamado por
__get__2leitura do campo que este objeto guarda
__set__2escrita nele
__delete__1remocao
__set_name__2o nome que ele recebeu na classe

Contexto (2)#

Entrar e sair de um bloco com limpeza garantida.

MétodoParâmetrosChamado por
__enter__0'with obj as x:' — o que 'x' recebe
__exit__0o fim do bloco, mesmo com erro

Assíncrono (5)#

await e percurso assíncrono.

MétodoParâmetrosChamado por
__await__0'await obj'
__aiter__0percurso assincrono
__anext__0o proximo item dele
__aenter__0'with' assincrono
__aexit__0o fim dele

Tipo (4)#

Como o objeto responde a perguntas sobre si mesmo.

MétodoParâmetrosChamado por
__instancecheck__1'e_um(x, Isto)'
__subclasscheck__1se um blueprint descende deste
__class_getitem__1Blueprint[Tipo] — generics
__init_subclass__1roda quando alguem herda deste

O que não existe#

  • Não há verificação de contrato. Declarar __iter__ sem __next__ só falha quando alguém tenta percorrer o objeto.
  • `__slots__` não é um método mágico — é uma declaração; veja slots.
  • Um mágico que devolve o tipo errado não é corrigido. __len__ devolvendo texto quebra no len(), não na declaração.