Representação Interna de Objetos em Python

Antes de mais nada, você já se perguntou sobre como funciona a representação interna de objetos em Python?

Primeiramente, quando nós começamos os nossos primeiros passos em programação, logo de cara nos deparamos com o conceito de classes. Isso acontece principalmente se nós estamos estudando qualquer linguagem “orientada a objetos”.

Em primeiro lugar, nós precisamos entender o que é uma classe em python.

Dentro da linguagem python (e não apenas nela), o conceito de classes é uma maneira de abstrair dados. Logo, quando estamos falando em dados em python, estamos falando obrigatoriamente de objetos e/ou relações entre objetos.

Objetos em Python

Como dito anteriormente, um objeto é uma maneira de abstrair informações internamente no python.

Todo objeto, obrigatoriamente possui uma identidade, um tipo e um valor.

Para verificar a identificação do objeto, é possível utilizar a função id()


Você pode entender esta identificação como um endereço do objeto na memória.

Caso você queira verificar a identidade de um objeto, é possível utilizar o operador is .

Em python, o operador is  é utilizado para verificar se dois ou mais objetos estão apontando para o mesmo identificador.

Representação Interna de Objetos em Python: Dunder Methods

Agora que já sabemos um pouco sobre o que o python entende por objetos, podemos seguir em frente e falar sobre o dunder methods.

Dunder methods, ou também conhecidos como magic methods (métodos mágicos em português).

Os dunder methods, são métodos especiais da linguagem, sendo a sua principal característica os dois underlines no início e final de seus nomes.

Aliás, o nome ‘Dunder’, por mais estranho que possa parecer, vem de ‘Double Underscore’.

Operadores Binários

Operador           Método
+                       object.__add__(self, other)
–                        object.__sub__(self, other)
*                        object.__mul__(self, other)
//                      object.__floordiv__(self, other)
/                        object.__div__(self, other)
%                      object.__mod__(self, other)
**                      object.__pow__(self, other[, modulo])
<<                     object.__lshift__(self, other)
>>                     object.__rshift__(self, other)
&                       object.__and__(self, other)
^                       object.__xor__(self, other)
|                        object.__or__(self, other)

Operadores de Atribuição

Operador          Método
+=                     object.__iadd__(self, other)
-=                      object.__isub__(self, other)
*=                      object.__imul__(self, other)
/=                     object.__idiv__(self, other)
//=                   object.__ifloordiv__(self, other)
%=                    object.__imod__(self, other)
**=                   object.__ipow__(self, other[, modulo])
<<=                  object.__ilshift__(self, other)
>>=                  object.__irshift__(self, other)
&=                    object.__iand__(self, other)
^=                    object.__ixor__(self, other)
|=                     object.__ior__(self, other)

Operadores Unários

Operador          Método
–                       object.__neg__(self)
+                      object.__pos__(self)
abs()                object.__abs__(self)
~                      object.__invert__(self)
complex()       object.__complex__(self)
int()                 object.__int__(self)
long()              object.__long__(self)
float()              object.__float__(self)
oct()                object.__oct__(self)
hex()               object.__hex__(self)

Operadores de Comparação

Operador          Método
<                      object.__lt__(self, other)
<=                    object.__le__(self, other)
==                    object.__eq__(self, other)
!=                     object.__ne__(self, other)
>=                    object.__ge__(self, other)
>                      object.__gt__(self, other)

Dunder Methods e o método __dict__

Já que o assunto é sobre representação interna de objetos em python, nada mais justo falarmos sobre um dos magic methods mais utilizados, o __dict__ .

Antes de continuarmos, vamos dar uma olhada em um pouco de código para exemplificar melhor o que é o método __dict__ em python:


Como podemos ver acima, o método __dict__ de um objeto contém todos os atributos definidos do mesmo. É exatamente o que acontece ao utilizarmos o  d.__dict__ .

Ele retorna exatamente um dict, contendo o nome e o valor dos atributos, e podemos utiliza-l0 tanto para acessar o valor de seus atributos, quanto para alterá-los.

Representação Interna de Objetos em Python: __getattr__

Você sabia que no caso de tentar acessar uma propriedade que não existe em sua classe, ainda é possível interceptar o evento, e no lugar de ter algum tipo de erro, retornar algo desejado?

O Python nos oferece dois magic methods que lidam muito bem com os atributos de nossas classes. São eles o __getattribute__  e o __getattr__ .

Legal não acha? Mas afinal, qual a diferença entre os dois?

A principal diferença entre eles é a ordem de chamada. Ao acessar uma propriedade de uma classe, o método __getattribute__ será invocado.

Caso a propriedade solicitada não seja encontrada, o método __getattr__ será invocado. Logo, é possível interceptarmos as chamadas a propriedades que não foram definidas previamente.

Isso pode ser muito poderoso, porém como diria o tio Ben, “com grandes poderes vêm grandes responsabilidades”.

Ao começarmos brincar com __getattr__, podemos acabar tendo comportamentos inesperados, inclusive estouro de pilha, caso o método __getattr__ comece a falhar.

Mas porque? Isso acontece, pois ao tentarmos acessar a propriedade, caso o método __getattr__ falhe, ele poderá ser invocado novamente, e novamente, e novamente, até exceder o limite de chamadas.

Para ilustrar melhor, vamos escrever um pouco de código!

No exemplo abaixo, eu mostro um exemplo bem simples, onde para todos os atributos que não existirem, será retornado o valor 10:


Legal não? Quanto mais eu estudo python, mais eu me apaixono por esta linguagem! Você pode conferir esta discussão no stackoverflow para entender melhor estes poderosos dunder methods!

Dunder Methods e o __setattr__

Assim como podemos interceptar tanto o acesso aos atributos, quanto o erro ao acessar um atributo, nós também podemos modificar o comportamento de um objeto ao definirmos um atributo.

Para isso, nós podemos usar o método mágico __setattr__ , que será invocado ao definirmos um atributo.

Vamos olhar o exemplo a seguir:


Ao executarmos o arquivo, nós teremos o seguinte resultado:


É possível também controlarmos se é possível ou não, definirmos determinado atributo.

No exemplo abaixo, nós adicionamos uma verificação para que não seja possível adicionar o atributo ‘f’:


Agora, ao executarmos o código, teremos o seguinte resultado:


Legal não?

E o que você achou do assunto? Deixe a sua opinião, ou se deseja aprender mais sobre a representação interna de objetos em python!

Quer aprender sobre Flask? Confira o nosso tutorial do flask framework.

No Responses

  1. Pingback: Mega Tutorial Python - O Guia Definitivo 4 de dezembro de 2018

Leave a Reply