How can I programmatically change the argspec of a function *not* in a python decorator?
Question: Very closely related to: [How can I programmatically change the argspec of a
function in a python
decorator?](http://stackoverflow.com/questions/3729378/how-can-i-
programmatically-change-the-argspec-of-a-function-in-a-python-decorato)

The decorator module provides the means to make a decorator function that
preserves the argspec of the decorated function.

If I define a function that is not used as a decorator, is there a way to copy
another function's argspec?

Example use case:

    
    
    class Blah(object):
        def foo(self, *args, **kwargs): 
            """ a docstr """
            result = bar(*args, **kwargs)
            result = result**2 # just so it's clear we're doing something extra here...
            return result
    
    def bar(x, y, z=1, q=2):
        """ a more useful docstr, saying what x,y,z,q do """
        return x+y*z+q
    

I would like to have `foo`'s argspec look like `bar`'s, but the source to stay
unchanged (i.e., `inspect.getsource(foo)` would still show the `result` junk).
The main purpose for this is to get sphinx docs and ipython's interactive help
to show the appropriate arguments.

As the answers to the other question said, the [decorator
package](http://code.google.com/p/micheles/source/browse/decorator/src/decorator.py)
shows a way to do this, but I got lost within the meat of that code. It seems
that the `decorator` package is recompiling the source, or something like
that. I had hoped a simpler approach, e.g. something like `foo.argspec =
bar.argspec`, would be possible.


Answer: A decorator is simply a function that does something with another function.
So, technically, you could put the required code directly underneath the `foo`
method and then, technically, you would be changing `foo` without using a
decorator, but it would be a horrible mess.

The easiest way to do what you want is going to be to make a decorator that
takes a second function (`bar` in this case) as an argument so it knows which
signature to copy. The class code would then look something like:

    
    
    class Blah(object):
        @copy_argspec(bar)
        def foo(self, *args, **kwargs): 
            """ a docstr """
            result = bar(*args, **kwargs)
            result = result**2 # just so it's clear we're doing something extra here...
            return result
    

You'll have to have `bar` defined before instead of after the class.

.  
.  
.  
. . . _time passes_ . . . .  
.  
.  

Okay, luckily I found an old decorator I could adapt.

`help(Blah.foo)` looks like this before decoration:

    
    
    Help on method foo in module __main__:
    
    foo(self, *args, **kwargs) unbound __main__.Blah method
        a docstr
    

and after decoration it looks like this:

    
    
    Help on method foo in module __main__:
    
    foo(self, x, y, z=1, q=2) unbound __main__.Blah method
        a more useful docstr, saying what x,y,z,q do
    

Here's the decorator I used:

    
    
    import inspect
    
    class copy_argspec(object):
        """
        copy_argspec is a signature modifying decorator.  Specifically, it copies
        the signature from `source_func` to the wrapper, and the wrapper will call
        the original function (which should be using *args, **kwds).  The argspec,
        docstring, and default values are copied from src_func, and __module__ and
        __dict__ from tgt_func.
        """
        def __init__(self, src_func):
            self.argspec = inspect.getargspec(src_func)
            self.src_doc = src_func.__doc__
            self.src_defaults = src_func.func_defaults
    
        def __call__(self, tgt_func):
            tgt_argspec = inspect.getargspec(tgt_func)
            need_self = False
            if tgt_argspec[0][0] == 'self':
                need_self = True
    
            name = tgt_func.__name__
            argspec = self.argspec
            if argspec[0][0] == 'self':
                need_self = False
            if need_self:
                newargspec = (['self'] + argspec[0],) + argspec[1:]
            else:
                newargspec = argspec
            signature = inspect.formatargspec(
                    formatvalue=lambda val: "",
                    *newargspec
                    )[1:-1]
            new_func = (
                    'def _wrapper_(%(signature)s):\n' 
                    '    return %(tgt_func)s(%(signature)s)' % 
                    {'signature':signature, 'tgt_func':'tgt_func'}
                       )
            evaldict = {'tgt_func' : tgt_func}
            exec new_func in evaldict
            wrapped = evaldict['_wrapper_']
            wrapped.__name__ = name
            wrapped.__doc__ = self.src_doc
            wrapped.func_defaults = self.src_defaults
            wrapped.__module__ = tgt_func.__module__
            wrapped.__dict__ = tgt_func.__dict__
            return wrapped
    

