import inspect
from functools import wraps
def add_value_checks(*settings):
def wrapping_function(func):
@wraps(func)
def wrapper(*args, **kwargs):
code = inspect.getsource(func)
hoax_code = code[code.find('\n')+1:code.find(':')+2]
hoax_code += '\treturn inspect.currentframe()\n'
if func.__name__ == 'run':
hoax_code = hoax_code.replace('run', 'run_hoax', 1)
print(hoax_code)
exec(hoax_code)
print(locals())
frame = run_hoax(*args, **kwargs)
targs, Args, Kwargs, values = inspect.getargvalues(frame)
for i in targs:
print(" %s = %s" % (i, values[i]))
return wrapper
return wrapping_function
@add_value_checks()
def run(a, b, c=True, d=5):
print("Hello World")
if __name__ == '__main__':
run(3,4)
我看到run_hoax()
中存在函数locals()
,但我仍然得到 NameError:name' run_hoax'未定义。可能的原因是什么?
这些简单的例子很好用:
In [1]: code = "def fun():\n\tprint(3)"
In [2]: exec(code)
In [3]: fun()
3
我无法理解这里的问题是什么。
答案 0 :(得分:1)
当您将其放入函数中时,您发布的示例将停止工作:
In [4]: def f():
...: code = "def foo():\n\treturn 1"
...: exec(code)
...: print(locals())
...: return foo()
...:
In [5]: f()
{'foo': <function foo at 0x7f780dcb48c8>, 'code': 'def foo():\n\treturn 1'}
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-0ec059b9bfe1> in <module>()
----> 1 f()
<ipython-input-4-fd87a1e83c39> in f()
3 exec(code)
4 print(locals())
----> 5 return foo()
NameError: name 'foo' is not defined
函数很特殊,因为它们引入了一个单独的局部作用域。编译函数时,该范围内的变量是固定的(变量的数量和名称,而不是它们的值)。您可以通过检查函数的.__code__.co_varnames
属性:
In [7]: f.__code__.co_varnames
Out[7]: ('code',)
固定的变量名称注册表是从函数内部查找名称时使用的。当您拨打exec
时,该注册表不会更新。
@Avezan显示的方法有效,因为它不使用局部变量 - 它使用locals
,其中 由您的exec调用更新。
@Ishan Srivastava的解决方案有效,因为它在全局命名空间中执行您的代码,但没有在编译时修复的限制。
有关Python的名称查找机制以及local
和exec
如何相互关联的详细说明,请参阅this blogpost。