检查 Python 函数是否引用了任何超出范围的内容
Checking if a Python function referenced anything out-of-scope
我正在探索在 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
是否有针对此的一些反射/分析工具?也许这可以通过 'trace' 模块以某种方式实现?
检查内置 locals() 函数。这将 return 本地范围内变量的字典。
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
您可以使用 inspect.getclosurevars
:
Get the mapping of external name references in a Python function or
method func to their current values. A named tuple
ClosureVars(nonlocals, globals, builtins, unbound) is returned.
nonlocals maps referenced names to lexical closure variables, globals
to the function’s module globals and builtins to the builtins visible
from the function body. unbound is the set of names referenced in the
function that could not be resolved at all given the current module
globals and builtins.
让我们看看它 returns 你的例子:
案例一:
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())
这里它检测到您正在全局范围内使用变量。
案例二:
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'})
这里检测到您正在使用模块的功能。
案例三:
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
我正在探索在 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
是否有针对此的一些反射/分析工具?也许这可以通过 'trace' 模块以某种方式实现?
检查内置 locals() 函数。这将 return 本地范围内变量的字典。
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
您可以使用 inspect.getclosurevars
:
Get the mapping of external name references in a Python function or method func to their current values. A named tuple ClosureVars(nonlocals, globals, builtins, unbound) is returned. nonlocals maps referenced names to lexical closure variables, globals to the function’s module globals and builtins to the builtins visible from the function body. unbound is the set of names referenced in the function that could not be resolved at all given the current module globals and builtins.
让我们看看它 returns 你的例子:
案例一:
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())
这里它检测到您正在全局范围内使用变量。
案例二:
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'})
这里检测到您正在使用模块的功能。
案例三:
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