Atributos em objetos do tipo function

Em um post anterior, nós vimos porque se diz que “tudo em Python é objeto”. Agora, vamos ver uma consequência interessante desse modelo.

Você já deve saber que o comando def é o comando de criação de um objeto do tipo function em Python. Ao interpretar o código abaixo

def funcao_qualquer():
    a = 0
    return a

o interpretador Python cria em memória um objeto chamado funcao_qualquer do tipo function. Isso ocorre da mesma maneira que o código abaixo cria um objeto do tipo int chamado x:

x = 42

A diferença entre o objeto function e o objeto int é que o primeiro é um objeto chamável (callable) e o segundo não. Dessa forma, o objeto function contém código executável dentro de si próprio. Vamos dar uma olhadinha no que temos dentro desse objeto:

>>> dir(funcao_qualquer)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

Sabendo dos campos e métodos disponíveis em objetos function, poderíamos fazer o seguinte (só para exemplificar):

>>> print funcao_qualquer.func_code.co_varnames
('a', )

Mas, mais do que acessar os atributos já existentes em um objeto function, nós também poderemos adicionar atributos a esses objetos. Por exemplo, se quisermos que a função que criamos (o objeto function) possua um contador indicando quantas vezes já foi chamada desde que foi criada, poderíamos defini-la da seguinte forma:

def minha_funcao():
    minha_funcao.contador_de_chamadas += 1
    # faça algo
    return 42
minha_funcao.contador_de_chamadas = 0

Assim, não precisamos criar variáveis globais para representar a contagem, e nem poluir a interface da função com parâmetros desnecessários. Cada vez que minha_funcao for chamada, o atributo interno contador_de_chamadas desse objeto será incrementado. Veja:

for i in range(0, 100):
    minha_funcao()
print minha_funcao.contador_de_chamadas  # imprime 100

Podemos até mesmo “pendurar” uma função como atributo de outra função:

>>> def f(x): return x*x
>>> minha_funcao.f = f
>>> minha_funcao.f(10)
100

Ou, usando uma função anônima:

>>> def f(): return 1
>>> minha_funcao.f = lambda x: x*x
>>> minha_funcao.f(9)
81

Dessa forma, podemos manipular nossas funções, isto é, nossas variáveis do tipo função, da mesma maneira que manipulamos variáveis do tipo lista, dicionário, string, etc. Isso porque elas realmente se tratam de um objeto como qualquer outro.

E lembre-se: com grandes poderes, vêm grandes responsabilidades. 🙂

Obrigado ao @eliasdorneles pela revisão.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s