Sei sulla pagina 1di 4

12/18/2017 Os métodos mágicos de Python | Python Help

OS MÉTODOS MÁGICOS DE PYTHON


Obs.: Códigos testados com a versão 2.7 do Python.

Quem está chegando em Python normalmente fica um pouco confuso ao ler o código de uma
classe e perceber um monte de métodos com underscores (__) no nome. Para entender o que são
esses métodos, vamos ver um exemplo.

Uma classe para números binários


Suponha que, por algum motivo, você receba a tarefa de implementar uma classe para

representação de números em base binária.

1 class Binario(object):
2
3 def __init__(self, valor_dec):
4 self.valor_dec = valor_dec
5 self.valor_bin = bin(self.valor_dec) #b
6
7 b = Binario(5)
8 print b

Se executarmos o código acima, teremos em b um objeto do tipo Binario, que representa o


valor 5 em base-2. 5 em base binária é 101. Porém, a execução da linha print b mostrou a
seguinte saída na tela:

<__main__.Binario object at 0x28286d0>

Isso porque o print executa a função str() no objeto recebido. Essa função, por sua vez, procura
por um método chamado __str__() no objeto a ser impresso. Como não definimos um método
com esse nome em nossa classe, o interpretador continua sua busca pelo método na classe que
está acima de Binario na hierarquia de classes, que é object. Lá ele encontra o método __str__,
que então retorna o texto <__main__.Binario object at 0x28286d0>, contendo o endereço do
objeto na memória.

O método __str__() deve retornar uma representação em forma de string do valor do objeto. Para
personalizar essa mensagem, ou seja, para fazer com que o print em objetos do
tipo Binariomostre uma sequência de 0s e 1s representando o número binário em questão, vamos
adicionar um método __str__() à nossa classe:

https://pythonhelp.wordpress.com/2013/03/11/os-metodos-magicos-de-python/ 1/4
12/18/2017 Os métodos mágicos de Python | Python Help
1 class Binario(object):
2
3 def __init__(self, valor_dec):
4 self.valor_dec = valor_dec
5 self.valor_bin = bin(self.valor_dec)
6
7 def __str__(self):
8 return "%s" % (self.valor_bin)
9
10 b = Binario(5)
11 print b

Agora, o resultado da execução do código acima é o seguinte:

0b101

Que é o formato retornado pela função bin() quando chamada. O prefixo 0b é adicionado para
indicar que se trata de um número binário. Podemos facilmente nos livrar desse prefixo para
representar o número binário na tela usando operadores de slicing:

1 def __str__(self):
2 return "%s" % (self.valor_bin[2:])

Beleza! Agora nosso número binário pode ser impresso corretamente na tela!

Sem perceber e sem chamá-los em lugar algum, já utilizamos dois métodos mágicos de Python:

__init__: método chamado para inicialização do objeto, logo após a sua construção;

__str__: método chamado pela função str() para obter o valor do objeto em forma de

string;

Chamamos eles de métodos mágicos porque eles resolvem o nosso problema sem sequer termos
que chamá-los. Quem os chama são códigos de outras classes/programas, que esperam que
nossos objetos forneçam tais métodos.

E se agora quisermos comparar objetos do tipo Binario em operações relacionais


como >, <, >=, <=, != e ==? Se tentarmos comparar duas instâncias de Binario usando algum
desses operadores, podemos ter respostas inesperadas, visto que eles não irão fazer o que
esperamos. O esperado é que a > b retorne Truese o valor de a for maior do que o valor de b.
Porém, onde definimos qual valor será usado para comparação dos objetos? Como não fizemos
isso, o interpretador irá usar o id de ambos os objetos para a comparação.

Para definir como os objetos de nossa classe serão comparados, podemos implementar o método
mágico __cmp__. Na documentação oficial, vemos instruções sobre como implementar esse método
para que nossos objetos possam ser comparados e usados em operações relacionais:

https://pythonhelp.wordpress.com/2013/03/11/os-metodos-magicos-de-python/ 2/4
12/18/2017 Os métodos mágicos de Python | Python Help

object.__cmp__(self, other)
Deve retornar um inteiro negativo se self < other, zero se self == other, ou um
número positivo se self > other.

Vamos então implementar o nosso método __cmp__. Podemos, para isso, usar o valor em decimal,
que armazenamos internamente na variável self.valor_dec:

1 def __cmp__(self, other):


2 if self.valor_dec > other.valor_dec:
3 return 1
4 elif self.valor_dec < other.valor_dec:
5 return -1
6 else:
7 return 0

Que poderia também ser escrito como:

1 def __cmp__(self, other):


2 return self.valor_dec - other.valor_dec

Tendo adicionado o código acima à classe Binario, agora podemos utilizar nossos objetos em
operações relacionais:

1 b = Binario(1)
2 c = Binario(2)
3 if b < c:
4 print "OK"

Mais uma vez, nosso método é executado sem que o chamemos explicitamente. Além dos métodos
que vimos aqui, existem vários outros métodos mágicos que podemos implementar em nossos

objetos para que o comportamento deles se pareça mais com o comportamento de objetos nativos
da linguagem. Vou listar alguns deles a seguir:

__add__(self, other): para adicionarmos a possibilidade de aplicação do operador + aos

nossos objetos. Para os outros operadores, também existem métodos mágicos


(subtração(-): __sub__; multiplicação(*): __mul__, divisão(/): __div__, módulo(%): __mod__,
potência(**): __pow__);
__call__(self): faz com que o objeto seja chamável (executável), assim como uma função

é;
__len__: retorna o comprimento do objeto (se for um container);

__getitem__(self, key): para containers, retorna o elemento correspondente à

chave key;

São muitos os métodos. Se você quiser conhecê-los melhor, sugiro dar uma olhada nesse texto (em
inglês): http://www.rafekettler.com/magicmethods.html.

https://pythonhelp.wordpress.com/2013/03/11/os-metodos-magicos-de-python/ 3/4
12/18/2017 Os métodos mágicos de Python | Python Help

Os métodos mágicos (magic methods), também chamados de métodos dunderscore (double-


underscore) ou de métodos especiais, são muito úteis pois permitem que objetos de nossas
classes possuam uma interface de acesso semelhante aos objetos nativos da linguagem. A
função sorted(), por exemplo, ordena os elementos de um iterável de acordo com o valor dos
objetos que a compõe. Se definirmos nosso método de comparação, a função sorted() irá usá-lo
para fazer a ordenação dos elementos da lista. Assim, é possível que códigos de terceiros lidem
com nosso código sem sequer conhecê-lo. Veja mais sobre esse conceito em: Polimorfismo.

https://pythonhelp.wordpress.com/2013/03/11/os-metodos-magicos-de-python/ 4/4

Potrebbero piacerti anche