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 blaSe 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!