使用自由变量警告每个(嵌套)函数(递归)

Evg*_*eev 6 python reflection closures nested-function

我想做以下事情:

for every nested function f anywhere in this_py_file:
    if has_free_variables(f):
        print warning
Run Code Online (Sandbox Code Playgroud)

为什么?主要是作为对其他地方描述的后期约束关闭的保险.即:

>>> def outer():
...     rr = []
...     for i in range(3):
...         def inner():
...             print i
...         rr.append(inner)
...     return rr
... 
>>> for f in outer(): f()
... 
2
2
2
>>> 
Run Code Online (Sandbox Code Playgroud)

每当我收到有关自由变量的警告时,我都会添加一个显式异常(在极少数情况下我会想要这种行为)或者像这样修复它:

...         def inner(i=i):

然后,行为变得更像Java中的嵌套类(其中任何要在内部类中使用的变量必须是final).

(据我所知,除了解决后期绑定问题之外,这还会促进更好地使用内存,因为如果函数"关闭"外部作用域中的某些变量,那么外部作用域不能被垃圾收集因为功能就在附近.对吗?)

我找不到任何方法来获取嵌套在其他函数中的函数.目前,我能想到的最好的方法是使用解析器,这看起来很多工作.

Jar*_*uen 2

考虑以下函数:

def outer_func():
    outer_var = 1

    def inner_func():
        inner_var = outer_var
        return inner_var

    outer_var += 1
    return inner_func
Run Code Online (Sandbox Code Playgroud)

__code__对象可用于恢复内部函数的代码对象:

outer_code = outer_func.__code__
inner_code = outer_code.co_consts[2]
Run Code Online (Sandbox Code Playgroud)

从这个代码对象中,可以恢复自由变量:

inner_code.co_freevars # ('outer_var',)
Run Code Online (Sandbox Code Playgroud)

您可以检查是否应检查代码对象:

hasattr(inner_code, 'co_freevars') # True
Run Code Online (Sandbox Code Playgroud)

从文件中获取所有函数后,这可能类似于:

for func in function_list:
    for code in outer_func.__code__.co_consts[1:-1]:
        if hasattr(code, 'co_freevars'):
            assert len(code.co_freevars) == 0
Run Code Online (Sandbox Code Playgroud)

对内部工作原理有更多了解的人可能可以提供更好的解释或更简洁的解决方案。