Bom, o post de hoje vai ser bem curto, pretendo apenas aproveitar uma oportunidade e abordar um assunto.
A alguns dias, um amigo do trabalho me perguntou se seria possível criar um decorator de decorators. O objetivo era simples, evitar a repetição de chamadas a decorators muito usados e essa a sintaxe feia abaixo:
@decorator_a
@decorator_b
@decorator_c
def teste(bla):
print bla
Se você tem dúvidas sobre o que é um decorator, veja a descrição na Wikipedia aqui.Depois de pensar um pouco, disse que seria possível com a forma mais verbosa de se usar um decorator. Vejam o exemplo abaixo:
def decorator_a(func):
def wrapper(*args, **kwargs):
print 'a'
return func(*args, **kwargs)
return wrapper
def decorator_b(func):
def wrapper(*args, **kwargs):
print 'b'
return func(*args, **kwargs)
return wrapper
def decorator_c(func):
def wrapper(*args, **kwargs):
print 'c'
return func(*args, **kwargs)
return wrapper
def decorator_all(func):
def wrapper(*args, **kwargs):
res_c = decorator_c(func)
res_b = decorator_b(res_c)
res_a = decorator_a(res_b)
return res_a(*args, **kwargs)
return wrapper
@decorator_all
def teste(bla):
print bla
if __name__ == '__main__':
teste('bla')
É importante reparar que a ordem das chamadas das funções, da linha 21 a 24, deve ser inversa a ordem usada na declaração com arroba (@). Isso se da pela forma que as funções são chamadas nas diferentes sintaxes e, em alguns casos, isso pode fazer diferença.
Veja a saída do código acima:
rafael@local ~$ python decorators.py a b c bla rafael@local ~$
Espero que tenham gostado. Um abraço e até o próximo post!
Muito show.
ResponderExcluirCaso interesse, mais chique ainda seria seria um decorator com parâmetros.
Sendo o segundo parâmetro do decorator_all uma lista, pode-se interar através dela e usar o decorator_all de forma genérica.
Não testei, mas acho que não haveria problemas.
Uma aplicação comum de decorator com parâmetros é uma das formas de configurar views no framework pyramid:
@view_config(context=Root, renderer='index.mako')
def index(context, request):
return {'index': context}
Obrigado Savio!
ResponderExcluirAcredito que seja possível sim, passando uma lista de funções decoradoras, ótima abordagem!