如何获取当前范围的非局部变量?函数vars
,locals
和globals
存在,但有一个函数可以获取nonlocals
吗?
为什么在调用vars
时列出的是非本地人?
我的问题是没有办法枚举当前范围内的可用变量,因为vars
或globals
都不包括非本地人AFAICT。
我经常在代码中使用vars
,如下所示:
'{meh[0]}/{meh[3]} {a}{b}{c}'.format(**vars())
如果这些变量中的任何变量都在包含函数的范围内,则会失败。
答案 0 :(得分:6)
从正在运行的代码中,您可以轻松获取非本地变量的名称 - 但以调用locals
获取字典的方式重新查找其内容有点棘手。
使用过的nonlocal
变量名称存储在当前运行的代码对象的co_freevars属性中。
因此,获取非本地名称是一个问题:
names = inspect.currentframe().f_code.co_freevars
然而,这些变量的内容存储在函数对象__closure__属性({1}},在Python 2中)中>相反。 (不是代码对象)。问题在于,如果没有“来自外部的帮助”,运行代码就没有简单的方法来获取它正在运行的函数对象。您可以访问链接到代码对象的frame对象,但是没有返回到函数对象的链接。 (对于顶级定义函数,可以显式使用函数已知名称,如func_closure
语句中所使用的那样,但是对于一个封闭函数,返回给调用者,无法知道其名称)
因此,必须采用一种技巧 - 通过使用gc模块(垃圾收集器)获取链接到当前代码对象的所有对象 - 有def
调用 - 它将返回所有链接到一个包含的代码对象的函数对象。
因此,在具有非本地变量的函数中,可以做到:
gc.get_referrers
因此检索nonlocals的名称和值。 但是如果您有多个该函数的实例(也就是说,如果感兴趣的函数多次创建多次调用生成它的函数),这将不起作用 - 因为所有这些实例都将链接到相同的代码对象。上面的例子假设只有一个函数与当前代码一起运行 - 并且在这种情况下可以正常工作。对factrory函数的另一个调用将创建另一个函数,可能还有非局部变量的其他值,但是使用相同的代码对象 - 上面的import inspect, gc
def a(b):
b1 = 2
def c():
nonlocal b1
print (b)
code = inspect.currentframe().f_code
names = code.co_freevars
function = [func for func in gc.get_referrers(code) if isinstance(func, FunctionType)][0]
nonlocals = dict (zip(names, (x.cell_contents for x in function.__closure__ )))
print(nonlocals)
return inspect.currentframe()
return c
c = a(5)
f = c()
列表生成器将检索所有这些,并随意选择其中的第一个。
“正确”函数是当前代码正在执行的函数 - 我试图想出一种检索此信息的方法,但无法实现。如果可以,我将完成此答案,但是现在,这无法帮助您检索非位置值。
(刚刚发现尝试使用带有非局部变量名称的“eval”也不会起作用)
看起来,在Python解释器的本机端内部运行时创建了唯一将当前运行帧链接到保存非局部变量值的函数对象的东西。我无法想到一种方法,在运行时使用ctypes模块查看解释器数据结构,这当然不适用于任何实际的生产代码。
底线:您可以可靠地检索非本地变量名称。但看起来你不能得到他们的名字,因为他们的名字是一个字符串(也不是重新绑定)。
您可以尝试在Python的错误跟踪器或Python-ideas邮件列表上打开“nonlocals”调用的功能请求。