我正在探索在Python中可以做什么,最近遇到了这个问题:在运行一个函数后,是否可以通过编程确定它是否引用了范围外的任何内容?例如:
import module1
y = 1
def foo1(x):
return y + x # yes - it has referenced 'y' which is out of foo1 scope
def foo2(x):
return module1.function1(x) # yes - it has referenced 'module1' which is out of foo2 scope
def foo3(x):
return x*x # no - it has only referenced 'x' which is an input to foo3, so the code executed within the scope of foo3
是否有一些反思/分析工具?也许这可以通过"跟踪"模块以某种方式实现?
您可以使用inspect.getclosurevars
:
获取Python函数或方法func设置为其当前值。命名元组将返回ClosureVars(非本地、全局、内置、未绑定(。非局部映射被引用的名称到词法闭包变量,全局到函数的模块全局和内建到可见的内建来自功能体。unbound是在给定当前模块的情况下根本无法解析的函数全局和内置。
让我们看看它为您的示例返回了什么:
情况1:
def foo1(x):
return y + x # yes - it has referenced 'y' which is out of foo1 scope
inspect.getclosurevars(foo1)
# ClosureVars(nonlocals={}, globals={'y': 1}, builtins={}, unbound=set())
在这里,它检测到您正在全局范围内使用变量。
情况2:
import colorsys
def foo2(x):
return colorsys.rgb_to_hsv(*x) # yes - it has referenced 'colorsys' which is out of foo2 scope
inspect.getclosurevars(foo2)
# ClosureVars(nonlocals={}, globals={'colorsys': <module 'colorsys' from '...\lib\colorsys.py'>}, builtins={}, unbound={'rgb_to_hsv'})
在这里,它检测到您正在使用模块的功能。
情况3:
def foo3(x):
return x*x # no - it has only referenced 'x' which is an input to foo3, so the code executed within the scope of foo3
inspect.getclosurevars(foo3)
# ClosureVars(nonlocals={}, globals={}, builtins={}, unbound=set())
在这里我们看到";没有什么异常";。
因此,我们可以将此过程封装在一个函数中,该函数看起来字段的any
(内置除外;即foo
可以使用abs
,没有问题(是否为非空:
import inspect
def references_sth_out_of_scope(fun):
closure_vars = inspect.getclosurevars(fun)
referenced = any(getattr(closure_vars, field) for field in closure_vars._fields if field != "builtins")
return referenced
用法:
>>> references_sth_out_of_scope(foo1)
True
>>> references_sth_out_of_scope(foo2)
True
>>> references_sth_out_of_scope(foo3)
False
>>> references_sth_out_of_scope(references_sth_out_of_scope) # :)
True
检查内置的locals((函数。这将返回本地作用域中变量的字典。
global_var = "Hello"
def foo():
local_var = "world"
if "local_var" in locals(): print(c)
if "global_var" in locals(): print(global_var)
>>> foo()
world