我想从包装它的装饰器中读取对象方法的本地值。 我可以从装饰器中访问函数和func_code,但似乎我能从中获得的是本地变量的名称,但不是它们的值。Python:有没有办法从包装它的装饰器中获取本地函数变量?
可能吗?
我想从包装它的装饰器中读取对象方法的本地值。 我可以从装饰器中访问函数和func_code,但似乎我能从中获得的是本地变量的名称,但不是它们的值。Python:有没有办法从包装它的装饰器中获取本地函数变量?
可能吗?
见https://stackoverflow.com/a/4249347/224295,http://code.activestate.com/recipes/577283-decorator-to-expose-local-variables-of-a-function-/
工作例如:
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
而是与功能的内部四处摆弄(这将打破,如果装饰功能是本机)的,写自己的包装,像这样:
<edit>
我才意识到我误解了问题,你不是试图获取函数属性,而是函数的局部变量值。你想要做的事情是不可能的,因为这些局部变量在函数运行之前不会被创建,并且只要函数返回或引发异常,函数的本地作用域就会被删除。
我离开我原来的答案,因为你可能会重写你的函数使用属性而不是本地变量,仍然使用这个装饰器来有效地做你想做的。
如果它正常工作,它将有助于您发布您当前尝试的内容以及一些具有预期输出的示例调用。 </edit>
当你需要一个具有属性的函数时,使用可调用类而不是普通函数定义通常是一个好主意。
这里是一个装饰,其中包装是一个可调用的类,它允许装饰轻松访问变量的一个例子,因为它们是包装类的实例变量:
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
导致my_func
运行得像这样:
>>> 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
不,这是不可能的访问被包装的函数里面的变量,因为(FJ在他的编辑指出的),他们不会在装饰在范围上的时间存在。
你要求的东西没有意义。
函数的局部变量始终没有值。考虑一下这个功能:
def foo(x):
y = x + 27
return y
什么是foo
的局部变量y
的价值?你不能回答,直到你拨打foo
(甚至直到y = x + 27
行被执行),这个问题才有意义。
而且当时不只是y
可能没有在这个时刻的值,有可能是的“飞行”的foo
执行任何数量的。可能有线程正在执行foo
,或者foo
可能是递归的(可能是间接的),因此即使在单个调用堆栈中也有多个调用正在进行。或foo
可能是一个生成器,因此即使没有递归也可能有很多正在执行的foo
执行(即,它们并非都可以从某个最外层的foo
范围内到达)。那么你会得到哪个y
的价值?
y
在foo
中的值只是不是一个明确定义的概念,除非您在foo
的范围内讨论。
鉴于Python的灵活性,我敢肯定,这是可以做到的堆栈帧反省,并找出foo
堆栈帧时,有一个目前生活在那个时候拔出它的局部变量的值。这对装饰者来说很难(如果不是不可能的话),因为(除非foo
是一个生成器)装饰者只能在“foo
”附近添加包装代码,这意味着装饰者控制的代码在foo
之前和之后运行,所以只有当foo
的堆栈帧不存在时才能控制。
我不会特别指出如何做到这一点,因为我不知道该怎么做。这听起来像是几乎肯定是一个坏主意,除非你正在编写一个调试器。
工程。尽管我确实同意它的一个坏主意,但我很想看看它是否可能。 – Harel 2012-02-09 10:14:20
好戏。我正在做一个调试器,必须从装饰函数中偷偷摸摸内部,并且它是合法有用的。有一件事要注意的是,tracer()不仅在装饰函数的返回上,而且在函数内调用的所有函数的返回上被调用。由于装饰后的函数总是有最后一次返回(因此最后设置_locals),所以在这种情况下无关紧要。 – Peter 2015-02-15 08:36:37