检查Python函数是否引用了超出范围的内容



我正在探索在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

最新更新