Search code examples
pythonpython-2.7ipythonpython-decorators

Python decorator to keep signature and user defined attribute


I have my simple decorator my_decorator which decorates the my_func.

def my_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    wrapper._decorator_name_ = 'my_decorator'
    return wrapper

@my_decorator
def my_func(x):
    print('hello %s'%x)

my_func._decorator_name_
'my_decorator'

Till here things work, but I can't see the actual signature of the function.

my_func?
Signature: my_func(*args, **kwargs)
Docstring: <no docstring>
File:      ~/<ipython-input-2-e4c91999ef66>
Type:      function

If I decorate my decorator with python's decorator.decorator, I can see the signature of my function but I can't have the new property which I have defined.

import decorator

@decorator.decorator
def my_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    wrapper._decorator_name_ = 'my_decorator'
    return wrapper

@my_decorator
def my_func(x):
    print('hello %s'%x)

my_func?
Signature: my_func(x)
Docstring: <no docstring>
File:      ~/<ipython-input-8-934f46134434>
Type:      function

my_func._decorator_name_
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-10-7e3ef4ebfc8b> in <module>()
----> 1 my_func._decorator_name_

AttributeError: 'function' object has no attribute '_decorator_name_'

How can I have both in python2.7?


Solution

  • For Python 3, using functools.wraps in standard library:

    from functools import wraps
    
    def my_decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        wrapper._decorator_name_ = 'my_decorator'
        return wrapper
    
    @my_decorator
    def my_func(x):
        print('hello %s'%x)
    
    print(my_func._decorator_name_)