我不是python的专家,所以在尝试理解变量作用域的细微差别时请多多包涵.

作为描述我所面临问题的简单示例,请说我有以下三个文件.

第一个文件是outside_code.py.由于某些限制,我无法修改此文件.必须照原样进行.它包含一些在某个时候运行评估的代码(是的,我知道评估是撒旦的产物,但这是以后的讨论).例如,假设它包含以下代码行:

def eval_string(x):
return eval(x)

第二个文件是一组用户定义的函数.我们称它为functions.py.它包含一些未知的函数定义,例如,让我们说functions.py包含一个函数,定义如下:

def foo(x):
print("Your number is {}!".format(x))

现在,我编写第三个文件,我们称它为main.py.其中包含以下代码:

import outside_code
from functions import *
outside_code.eval_string("foo(4)")

我用*导入了来自functions.py的所有函数定义,因此main.py应该可以访问它们,而无需执行诸如functions.foo()之类的事情.我还导入了outside_code.py,以便可以访问其核心功能,即包含评估值的代码.最后,我在outside_code.py中调用该函数,并传递一个与functions.py中定义的函数相关的字符串.

在简化的示例中,我希望代码打印出“您的数字是4!”.但是,我收到一条错误消息,指出未定义’foo’.显然,这意味着outside_code.py中的代码无法访问main.py中存在的同一foo函数.所以我需要以某种方式使foo可以访问它.谁能确切地告诉我foo的范围,以及如何扩展它以覆盖我实际要使用的空间?解决我的问题的最佳方法是什么?

解决方法:

您必须将这些名称添加到outside_code的范围内.如果outside_code是常规的Python模块,则可以直接执行以下操作:

import outside_code
import functions
for name in getattr(functions, '__all__', (n for n in vars(functions) if not n[0] == '_')):
setattr(outside_code, name, getattr(functions, name))

这将使用所有名称函数导出(您将从函数import *导入的名称),并将对相应对象的引用添加到outside_code中,以便outside_code.eval_string()内部的eval()可以找到它们.

您可以使用ast.parse() function从表达式生成解析树,然后再将其传递给eval_function(),然后从表达式中提取所有全局名称,仅将这些名称添加到outside_code即可,以限制破坏,可以这么说,但是您仍然破坏其他模块的名称空间以使其工作.

请注意,这几乎与首先使用eval()一样邪恶,但是如果您不能告诉其他模块中的eval()接受命名空间参数,则这是您唯一的选择.这是因为默认情况下,eval()使用运行它的模块的全局名称空间作为名称空间.

但是,如果您的eval_string()函数实际上接受更多参数,请寻找名称空间或全局选项.如果存在,该函数可能看起来像这样:

def eval_string(x, namespace=None):
return eval(x, globals=namespace)

之后,您可以执行以下操作:

outside_code.eval_string('foo(4)', vars(functions))

其中vars(functions)为您提供functions模块的名称空间.

标签:python-3-x,python