我有这样的代码:
globals_defined = {'add': my_add_fn, 'divide': my_divide_fn}
eval_result = eval(<some code>, {data: {'name_1': 'NAME1', 'name_2': 'NAME2'}, globals_defined)
我想在eval中设置一个全局变量,然后能够访问它。所以喜欢:
globals_defined = {'add': my_add_fn, 'divide': my_divide_fn, count_iterations: 0}
eval_result = eval(<some code>, {data: {'name_1': 'NAME1', 'name_2': 'NAME2'}, globals_defined)
print 'iterations: ' + str(globals_defined['count_iterations'])
理想情况下,会打印一个修改后的count_iterations值。在eval中,my_add_fn会执行类似下面的操作来增加它:
def my_add_fn():
global count_iterations
count_terations += 1
return 'blah!'
编辑:我应该先添加这个。是的,我需要使用eval。此eval最初来自用户输入,但已被解析为抽象语法树,该树拒绝除少数几个数学运算之外的所有操作。然后,该AST是定义了一些自定义函数定义的评估。
听起来我不能这样做。
答案 0 :(得分:3)
你不应该使用eval开始。 但是,由于您没有显示您在那里运行的代码,因此无法建议替代方案。
事实是Python的eval
只执行表达式 - 而Python中的赋值是statements
- 你通常不能在eval中有一个赋值。
解决这个问题的方法就是使用exec
而不是eval。默认情况下,exec
将使用运行它的模块的全局变量,因此,执行代码中的任何赋值都将影响全局命名空间。
如果您将字典作为第二个参数传递给exec
,它将使用该字典作为其全局字典 - 然后您可以通过分配修改该字典中的值。
这是关于eval和exec的一般声明 - 你的具体问题是你(可能)试图在eval中调用一个函数 - add()
- 它在globals_defined
字典中公开了本身。问题是你的模块中定义了你的add函数 - 在eval(或exec)范围之外。 my_add_fn
函数的全局变量不是传递给eval的globals
,而是模块全局变量本身。因此,它访问的变量count_iterations
位于模块范围内,而不是globals_defined
字典内。
当然有办法解决这个问题。最好的是:不使用eval(或exec)。
你在最后一行的打印习语暗示你是Python的新手 - 否则你就会知道存在的字符串格式化的强大方法。
这就是说:您可以调用存储在字典中的函数,就像您可以访问字典中的任何元素一样 - 即:
globals_defined["add"] ()
将my_add_fn
所有功能 - 这是您如何摆脱使用“eval”的必要条件。
最后,回到原来的问题 - 解决问题的一种方法是让你的函数不依赖于它的全局命名空间,而是接收和返回参数 - 然后你做出函数返回的值的赋值在它之外 - 在你的exec字符串范围内 - 因此:
def my_add_fn(count):
return 'blah!', count+1
global_dict = {"add": my_add_fn, "count_iterations": 0}
exec("result, count_iterations = add()", global_dict)
print "Count = {}".format(global_dict["count_iterations"])
答案 1 :(得分:0)
为什么要尝试使用全局命名空间?为什么不构造一个特定的本地命名空间来将函数传递给eval
?将globals()
作为全局命名空间传递给eval
或exec
的问题在于,您将命名空间的控制权交给您退出的代码,因此(例如)如果它绑定到你已经在使用你的价值的名字将被覆盖。