我对函数变量范围和返回有一个相当奇怪的问题。 有没有办法在被调用函数返回值后检查调用者中被调用函数的范围?
用例很简单:在Flask视图中,我想绕过locals()
到我的模板。我可以通过约定定义我需要的模板,并在每个视图中返回一个字典困扰我。
答案 0 :(得分:1)
函数返回后,其范围不再存在。这使得在函数返回后获取范围会有问题。
但是,使用Python的跟踪或配置文件功能,可以运行一些代码,就像函数 about 一样,并在那时从其堆栈帧中提取本地。然后可以将它们放在某处,并使用包装函数返回(或代替)被调用函数的返回值。
这是一个可以用于这个邪恶目的的装饰器。请记住,这个实现是一个可怕的黑客,使用它只是为了方便是不好的风格。我可能会想到合法用途......给我几天时间。此外,它可能无法与非CPython实现(实际上可能不会)。
import sys, functools
def givelocals(func):
localsdict = {}
def profilefunc(frame, event, arg):
if event == "call":
localsdict.clear()
elif event == "return":
localsdict.update(frame.f_locals)
return profilefunc
@functools.wraps(func)
def wrapper(*args, **kwargs):
oldprofilefunc = sys.getprofile()
sys.setprofile(profilefunc)
try:
return func(*args, **kwargs), dict(localsdict)
except Exception as e:
e.locals = dict(localsdict)
raise
finally:
sys.setprofile(oldprofilefunc)
return wrapper
示例:
@givelocals
def foo(x, y):
a = x + y
return x * y
>>> foo(3, 4)
(12, {'y': 4, 'x': 3, 'a': 7})
如果你有一些任意函数,你想用它来装饰,因为它在你没有写的模块中,你可以动态创建包装并调用它:
def foo(x, y):
a = x + y
return x * y
>>> givelocals(foo)(3, 4)
(12, {'y': 4, 'x': 3, 'a': 7})
或者存储包装器并稍后调用它:
locals_foo = givelocals(foo)
>>> locals_foo(3, 4)
(12, {'y': 4, 'x': 3, 'a': 7})
包装器返回实际返回值的元组和locals字典。如果引发异常,则异常对象的.locals
属性将设置为locals dict。
最后一点:我在这里使用Python的配置文件功能,因为它仅在函数调用和返回时调用。如果您使用的是2.6之前的Python版本,那么您没有分析,因此您需要使用跟踪代替。配置文件功能也可以作为书面跟踪功能使用,您只需使用gettrace()
和settrace()
而不是相应的配置文件相关功能。但是,由于为每一行调用了跟踪,因此包装函数可能会明显变慢。