运行时加载Python代码

18 投票
9 回答
38115 浏览
提问于 2025-04-15 19:15

我想在程序运行时加载一个 .py 文件。这个 .py 文件其实是一个配置文件,格式如下:

var1=value  
var2=value  
predicate_function=func line : <return true or false>  

加载这个文件后,我希望能够访问里面的 var1var2predicate_function。对于每一行数据,我会把它传给这个判断函数,如果返回的是假(false),我就会忽略这一行。

不过,我不太确定怎么在运行时加载一个 Python 文件并访问它的变量。

补充说明:我可能需要传入多个这样的配置文件到主程序中,而我在运行之前并不知道这些文件的名字。谷歌告诉我应该使用 __import__,但我不太清楚怎么正确使用这个方法来访问导入文件里的变量。

9 个回答

7

要使用另一个Python模块,你需要导入它。有些人提到过execfile,但这方法比较麻烦而且有风险。使用execfile会让你的命名空间变得混乱,甚至可能会影响你正在运行的代码。当你想要访问另一个Python源文件时,最好使用import语句。

更好的做法是根本不使用Python文件来配置,而是使用内置的ConfigParser模块或者像JSON这样的序列化格式。这样一来,你的配置文件就不会执行任意(可能是恶意的)代码,也不需要人们懂Python就能配置你的程序,而且可以很方便地通过程序进行修改。

16

根据Python官方文档的说明,如果你只是想通过名字导入一个模块,可以在使用__import__之后,在sys.modules字典中查找它。

假设你的配置在myproject.mymodule中,你可以这样做:

module_name = 'myproject.mymodule'

import sys
__import__(module_name)
mymodule = sys.modules[module_name]

# Then you can just access your variables and functions
print mymodule.var1
print mymodule.var2
# etc...

你也可以使用__import__语句的返回值,但你需要完全理解Python是如何处理命名空间和作用域的

10

你只需要能够动态地指定要导入的内容,然后动态地获取这些变量。

假设你的配置文件是 bar.py,内容如下:

x = 3
y = 4
def f(x): return (x<4)

那么你的代码应该像这样:

import sys

# somehow modnames should be a list of strings that are the names of config files
#
# you can do this more dynamically depending on what you're doing                                                                                                     
modnames = ['bar']

for modname in modnames:
  exec('import %s' % modname)

for modname in modnames:
  mod = sys.modules[modname]
  for k in mod.__dict__:
    if k[:2] != '__':
      print modname, k, mod.__dict__[k]

我得到了这个输出:

bar f <function f at 0x7f2354eb4cf8>
bar x 3
bar y 4

这样你至少可以获取到所有的变量和函数。我不太明白你想从谓词函数中得到什么,但也许你现在可以自己搞定了。

撰写回答