Python closures and replacing surrounding scope
我知道,当使用groovy闭包时,我可以更改闭包上的
我能用Python做类似的事情吗?
具体来说,如果采用以下代码:
1 2 3 4 5 6 7 8 9 10 | def configure(): build() def wrap(function): def build(): print 'build' function() wrap(configure) |
我想打印"build"(只对
一些注意事项:
我不想将函数传递到
我也不想全局定义这些函数,因为可能会有大量的函数可以由
是否是一个好的方法来做这是有争议的,但这里有一个不修改全局名称空间的解决方案。
1 2 3 4 5 6 7 8 9 10 11 | def configure(): build() def wrap(f): import new def build(): print 'build' new.function(f.func_code, locals(), f.func_name, f.func_defaults, f.func_closure)() wrap(configure) |
。
我在如何修改python中的本地名称空间中找到了它。
这在没有元编程的情况下是可行的。让
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def default_build(): print"default build" def configure(build_func=None): build_func = build_func or default_build build_func() def wrap(func): def build(): print"wrap build" func(build) wrap(configure) |
通过这种方式可以清楚地表明,
您也可以随意处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def build(): print"default build" def configure(): build() def wrap(func): def _build(): print"wrap build" old_build = func.func_globals['build'] func.func_globals['build'] = _build func() func.func_globals['build'] = old_build |
号
如果你觉得自己很疯狂,很了不起,可以看看这篇关于动态范围界定的文章。
基本上,其思想是修改函数的字节码(使用
1 2 3 4 5 6 7 8 9 10 11 12 | code = byteplay.extractcode(function) newbytecode = [] for opcode, arg in code.code: if opcode in (NONLOCAL_CODES): opcode = LOCAL_EQUIVALENT newbytecode.append((opcode, arg)) code.code = newbytecode return code.to_code() |
这比这稍微复杂一点,但本文提供了一些很好的信息。
他还建议不要在生产中使用它。D
您需要使用
1 2 3 4 5 6 | def wrap(function): global build def build(): print 'build' function() |
。
一种方法是在
1 2 3 4 5 6 7 8 9 10 11 | def configure(): build() def wrap(function): global build def build(): print 'build' function() wrap(configure) |
但是,我并不推荐这样做,因为它会污染名称空间。