On Fri, 11 Mar 2005 11:55:51 -0500, Victor Ng <[EMAIL PROTECTED]> wrote:
>Is there a way to preserve the argspec of a function after wrapping it >in a closure? > >I'm looking for a general way to say "wrap function F in a closure", >such that inspect.getargspec on the closure would return the same >(args, varargs, varkw, defaults) tuple ass the enclosed function. > >The typical code I'm using is something like this: > >def wrapFunc(func): > def tmpWrapper(*args, **kwargs): > return func(*args, **kwargs) > tmpWrapper.func_name = func.func_name > return wrapFunc > >This preserves the function name - how do I do more? Probably you could use the inspect.getargspec(func) info to build a wrapper with the identical signature that would call func passing everything through 1:1, but that would seem kind of useless, unless you want to substitute some closure values into the func call and get a currying effect. In that case, your new signature should probably be changed to reflect the real effective signature of the curried function. I recently posted a byte-code-munging decorator hack that accomplishes some of that. E.g., (I keep presets.py in my ut package, where I accumulate miscellaneous experimental untility stuff) >>> from ut.presets import presets, curry >>> @curry(y=123) ... def foo(x, y): return x*y ... >>> import inspect >>> inspect.getargspec(foo) (['x'], None, None, None) >>> import dis >>> dis.dis(foo) 1 0 LOAD_CONST 1 (123) 3 STORE_FAST 1 (y) 3 6 LOAD_FAST 0 (x) 9 LOAD_FAST 1 (y) 12 BINARY_MULTIPLY 13 RETURN_VALUE And without the currying decorator: >>> def foo(x, y): return x*y ... >>> inspect.getargspec(foo) (['x', 'y'], None, None, None) >>> dis.dis(foo) 1 0 LOAD_FAST 0 (x) 3 LOAD_FAST 1 (y) 6 BINARY_MULTIPLY 7 RETURN_VALUE Basically, the curry decorator here injects a local assignment and adjusts the line map and signature and a few other tweaks, depending. This doesn't wrap the function though, it modifies it. I haven't tried decorating indirectly... Hm... Faking decoration of foo with getf to substitute the func passed ... >>> def wrap(func, y): ... def getf(f): return func ... @curry(y=y) ... @getf ... def foo(): pass ... foo.func_name = func.func_name ... return foo ... >>> def bar(x, y): return x+y ... >>> wbar = wrap(bar, 1000) >>> wbar <function bar at 0x02F1AAE4> >>> bar(123) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: bar() takes exactly 2 arguments (1 given) oops, that should have been wbar ... >>> wbar(123) 1123 >>> inspect.getargspec(wbar) (['x'], None, None, None) >>> import dis >>> dis.dis(wbar) 1 0 LOAD_CONST 1 (1000) 3 STORE_FAST 1 (y) 3 6 LOAD_FAST 0 (x) 9 LOAD_FAST 1 (y) 12 BINARY_ADD 13 RETURN_VALUE >>> inspect.getargspec(bar) (['x', 'y'], None, None, None) >>> dis.dis(bar) 1 0 LOAD_FAST 0 (x) 3 LOAD_FAST 1 (y) 6 BINARY_ADD 7 RETURN_VALUE I don't know where this is leading. What was your goal again? Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list