solovyov.net

Пара слов о декораторах

3 min read · python, programming

Всем известна одна особенность декораторов - если просто, без всяких ухищрений, написать декоратор и применить его к функции, то любые способы определить имя функции, посмотреть её документацию и т.д. окажутся бесполезными - декоратор их заменяет своими. Для примера возьмём таки начавший понемногу расходиться по проектам render_to:

def render_to(tmpl):
    def renderer(func):
        def wrapper(request, *args, **kw):
            output = func(request, *args, **kw)
            if not isinstance(output, dict):
                return output
            return render_to_response(tmpl, output, 
                   context_instance=RequestContext(request))
        return wrapper
    return renderer

Конечно, можно дописать пару строк к возврату враппера и получить в принципе работающий механизм:

        wrapper.__name__ = func.__name__
        wrapper.__doc__ = func.__doc__
        return wrapper

Но на самом деле это не самый красивый метод. Куча всяких руководств для начинающих по написанию декораторов всегда рекомендует юзать модуль Мишеля Симионато - decorator. В принципе, всё конечно просто отлично, но есть у него огромный недостаток - это дополнительная библиотека, в то время как есть отличное решение из стандартной библиотеки - functools.wraps. Его использование ничем не отличается от использования decorator‘а:

from functools import wraps

def render_to(tmpl):
    def renderer(func):
        @wraps(func)
        def wrapper(request, *args, **kw):
            output = func(request, *args, **kw)
            if not isinstance(output, dict):
                return output
            return render_to_response(tmpl, output, 
                   context_instance=RequestContext(request))
        return wrapper
    return renderer

И всё становится белым и пушистым. :-) Один момент непонятен - почему его не пишут во всех этих руководствах для начинающих? Ведь эти начинающие с течением времени становятся продолжающими и точно так же не знают о простой и приятной штуке прямо в stdlib‘е.

If you like what you read — subscribe to my Twitter, I always post links to new posts there. Or, in case you're an old school person longing for an ancient technology, put a link to my RSS feed in your feed reader (it's actually Atom feed, but who cares).

Other recent posts

ngrok for the wicked, or expose your ports comfortably
PostgreSQL collation
History snapshotting in TwinSpark.js
Code streaming: hundred ounces of nuances
Useful shell prompt