Зачем здесь переопределяется у обертки описание функции и ее имя в декораторе?

def ajax_required(f):
    def wrap(request, *args, **kwargs):
        if not request.is_ajax():
            return HttpResponseBadRequest()
        return f(request, *args, **kwargs)
    wrap.__doc__=f.__doc__
    wrap.__name__=f.__name__
    return wrap

Я понимаю, на мой взгляд, как работают декораторы: Например(бесполезный, но ради примера):

@ajax_required
def main(request):
    return JsonResponse({'status':'ok'})

Что происходит? Происходит следующее wrap = ajax_required(main), обертка еще не отработала, мы вернули функцию wrap, тело которой внутри ajax_required.Далее делается следующее wrap(request), и отрабатывает обертка, которая проверяет запрос на ajax.Так вот не могу понять зачем нам перед тем как вернуть функцию wrap делать:

wrap.__doc__ = f.__doc__
wrap.__name__ = f.__name__

Код с таким декоратором взят из книги, в книге не объяснилось, почему именно так и направили на изучение декораторов ссылкой на документацию:) За что отвечают эти "магические переменные" вроде знаю


Ответы (1 шт):

Автор решения: Sergey Gornostaev

Python - очень рефлексивный язык, в нём всё является объектом и каждый объект несёт в себе много мета-информации. На это опираются многие утилиты, библиотеки и сама виртуальная машина Python. Наивный декоратор стирает оригинальное имя функции и её docstring. Соответственно, для неё перестаёт работать help, портятся сообщения об ошибках и возникают прочие неудобства.

Но обычно, вручную подобные действия не делают. Для этого в стандартной библиотеке есть декоратор wraps.

→ Ссылка