Python: Is there a way to get a local function variable from within a decorator that wraps it?
See https://stackoverflow.com/a/4249347/224295, http://code.activestate.com/recipes/577283-decorator-to-expose-local-variables-of-a-function-/
Working example:
import sys
class persistent_locals(object):
def __init__(self, func):
self._locals = {}
self.func = func
def __call__(self, *args, **kwargs):
def tracer(frame, event, arg):
if event=='return':
self._locals = frame.f_locals.copy()
# tracer is activated on next call, return or exception
sys.setprofile(tracer)
try:
# trace the function call
res = self.func(*args, **kwargs)
finally:
# disable tracer and replace with old one
sys.setprofile(None)
return res
def clear_locals(self):
self._locals = {}
@property
def locals(self):
return self._locals
@persistent_locals
def func():
local1 = 1
local2 = 2
func()
print func.locals
What you're asking for doesn't really make sense.
A function's local variables don't have values all the time. Consider this function:
def foo(x):
y = x + 27
return y
What is the value of foo
's local variable y
? You can't answer, the question doesn't even make sense until you call foo
(and even then, not until the line y = x + 27
is executed).
And even then it's not just that y
might not have a value at this moment, there could be any number of "in flight" executions of foo
. There could be threads executing foo
, or foo
could be recursive (possibly indirectly) so that there is more than one call in progress even in a single call stack. Or foo
could be a generator, so there could be many in-flight foo
executions even without recursion (i.e. they're not all reachable from some outermost foo
scope). So which y
would you get the value of?
The value of y
in foo
just isn't a well-defined concept unless you're talking about within the scope of foo
.
Given Python's flexibility, I'm pretty sure it's possible to do stack frame introspection and find a stack frame for foo
when there is one currently live and pull out the values of its local variables at that time. This would be pretty hard (if not impossible) to do with a decorator, because (unless foo
is a generator) the decorator can only add wrapper code "around" foo
, which means the code controlled by the decorator runs before and after foo
runs, so you only get control when foo
's stack frame doesn't exist.
I'm not going to give specific pointers on exactly how to do this, because I don't know how to do it. It sounds like it's almost certainly a bad idea though, unless you're writing a debugger.
<edit>
I just realized I misread the question and that you are not trying to get function attributes, but local variable values from the function. What you want to do is not possible because those local variables are not created until the function is run, and the local scope for the function is deleted as soon as the function returns or raises an exception.
I am leaving my original answer because you could potentially rewrite your function to use attributes instead of local variables and still use this decorator to effectively do what you want.
It would be helpful for you to post what you have currently attempted and some example calls with expected output if it was working correctly.</edit>
When you need a function with attributes, it is generally a good idea to use a callable class instead of a normal function definition.
Here is an example of a decorator where the wrapper is a callable class, which allows the decorator to access variables easily, because they are instance variables of the wrapper class:
def deco(func):
class Wrapper(object):
def __init__(self):
self.foo = None
def __call__(self, *args):
print 'old foo:', self.foo
result = func(*args)
print 'new foo:', self.foo
return result
return Wrapper()
@deco
def my_func(new_foo):
my_func.foo = new_foo
Which results in my_func
behaving like this:
>>> my_func('test')
old foo: None
new foo: test
>>> my_func.foo
'test'
>>> my_func(42)
old foo: test
new foo: 42
>>> my_func.foo
42