9

Possible Duplicate:
How can I programmatically change the argspec of a function in a python decorator?

argspec is a great way to get arguments of a function, but it doesn't work when the function has been decorated:

def dec(func):
    @wraps(func)
    def wrapper(*a, **k)
        return func()
    return wrapper


@dec
def f(arg1, arg2, arg3=SOME_VALUE):
    return

import inspect
print inspect.argspec(f)

-----------

ArgSpec(args=[], varargs='a', keywords='k', defaults=None)

Argspec should return arg1, arg2, arg3. I think I need to define wrapper differently as to not use *a and **k, but I don't know how.

Community
  • 1
  • 1
priestc
  • 33,060
  • 24
  • 83
  • 117
  • 1
    I'm glad there is a 3rd party module that solves our problem, so thanks to @MuMind for pointing it out, but *why* isn't this handled by the Python standard library's own ``functools.wraps`` decorator, as you and I both expected? That's exactly what it's for, after all. Bug report? – smheidrich Mar 24 '15 at 17:44
  • For those interested, I opened the can of worms here: http://bugs.python.org/issue23764 – smheidrich Mar 26 '15 at 01:00

1 Answers1

10

The decorator module preserves them fine:

from decorator import decorator
@decorator
def dec(func, *a, **k):
    return func()

@dec
def f(arg1, arg2, arg3=1):
    return

import inspect
print inspect.getargspec(f)
ArgSpec(args=['arg1', 'arg2', 'arg3'], varargs=None, keywords=None, defaults=(1,))

You probably can get the same effect by manually copying some __foo__ attributes from the function to the wrapper function, but anyway the decorator module demonstrates it's possible and maybe gives you a starting point.

Mu Mind
  • 10,935
  • 4
  • 38
  • 69
  • 1
    This answers my question, but I'm bummed that the decorator module doesn't seem to support decorators that take parameters. – priestc Sep 24 '12 at 04:20
  • You mean like a decorator "factory", like `@dec(1, 2)`? – Mu Mind Sep 24 '12 at 04:21
  • 2
    Easily done: just define a factory function that takes some arguments, defines an inner function with `@decorator`, and returns the inner function. It's confusing because being another level deeper it starts looking similar to the functools version, but it has the right argspec and should work exactly how you want. – Mu Mind Sep 24 '12 at 05:25