3

My decorator is "closure-style"; it does some work before returning the decorated function.

Borrowing from this famous question: Preserving signatures of decorated functions

def args_as_ints(f):

    time.sleep(1) # hard at work

    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g

functools.wraps does not preserve the signature in Python 2.

from functools import wraps

def args_as_ints(f):

    time.sleep(1) # hard at work

    @wraps(f) 
    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g


@args_as_ints
def funny_function(x, y, z=3):
    """Computes x*y + 2*z"""
    return x*y + 2*z

help(funny_function)

shows

Help on function funny_function in module __main__:

funny_function(*args, **kwargs)
    Computes x*y + 2*z

The decorator module doesn't seem to support this style of decorator.

Also related: Preserve Signature in Decorator python 2

user357269
  • 1,835
  • 14
  • 40

2 Answers2

0

You can use the wrapt module.

Keep in mind that wrapt decorators have a different interface than standard python decorators. I strongly recommend reading the wrapt documentation. Anyway, here's a basic implementation of your decorator with wrapt.decorator:

import wrapt

def args_as_ints(f):
    time.sleep(1) # hard at work

    @wrapt.decorator
    def g(f, instance, *args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)

    return g(f)  # apply the decorator to the function

Note that my implementation completely ignores the instance argument, so it won't work correctly for instance methods.

It does, however, maintain the decorated function's signature:

Help on function funny_function in module __main__:

funny_function(x, y, z=3)
    Computes x*y + 2*z
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
0

Managed to find the answer here: https://decorator.readthedocs.io/en/latest/tests.documentation.html#dealing-with-third-party-decorators

def args_as_ints(f):

    time.sleep(1)

    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)

    return decorator.FunctionMaker.create(
        f, 'return decfunc(%(signature)s)',
        dict(decfunc=g, __wrapped__=f))
user357269
  • 1,835
  • 14
  • 40