在运行时加载Python代码

18

我想在运行时加载一个.py文件。这个.py文件基本上是一个配置文件,具有以下格式:

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

加载该文件后,我想能够访问var1var2predicate_function。对于每一行,我将把它传递给谓词函数,如果它返回false,我将忽略它。

无论如何,我不知道如何在运行时加载Python文件并访问其变量。

澄清一下:可能有任意数量的这些配置文件需要传递给主程序,我在运行时不知道它们的名称。Google告诉我应该使用__import__。我不确定如何正确使用这种方法然后访问导入文件的变量。


您可以在运行时将文件路径附加到sys.path上:>>>import sys 然后 >>>sys.path.append(r'C:\path_to_file') 最后 >>>import myfile - Hank Lenzi
9个回答

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如何处理命名空间和作用域


2
嗯,不是这样的,在我的例子中,它会返回“myproject”模块而不是“myproject.mymodule”。直接从文档中得知:当名称变量形式为package.module时,通常返回顶级包(即第一个点之前的名称),而不是由名称指定的模块。 - Clément

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

那么你至少有所有的变量和函数。我并没有完全理解你从谓词函数中想要什么,但现在也许你可以自己得到答案了。


7

要访问另一个Python模块,您需要导入它execfile 已经被一些人提到过,但它很混乱且危险。 execfile 混淆了您的命名空间,甚至可能破坏您正在运行的代码。当您想要访问另一个Python源文件时,请使用import语句。

更好的方法是根本不使用Python文件进行配置,而是使用内置模块ConfigParser或像JSON这样的序列化格式。这样,您的配置文件不允许执行任意(可能恶意)代码,不需要人们了解Python来配置您的程序,并且可以轻松地以编程方式进行修改。


实际上,我将我的配置文件设置为Python文件的原因是因为我想让配置文件包含一些(谓词)函数。否则,我只需读取文本文件,拆分字符串并读入字典即可。 - Shahbaz

7
如果导入的模块在常规搜索路径上,你可以使用 __import__
如果需要从文件系统中的任意路径加载模块,请使用 imp.load_module
一定要考虑加载任意用户指定代码的安全性问题。

3

由于Python版本并没有明确说明,值得指出的是,在新版本的Python中,imp模块已经被废弃,推荐使用importlib模块。可参见此处示例


3
在Python 2.*中,execfile是可用的(我建议传递一个特定的字典,并从那里访问变量--正如文档中的注释所说, execfile 无法影响调用函数的 locals()字典)。

在Python 3.*中,已删除execfile,因此请改为执行以下操作:

with open('thefile.py') as f:
  exec(f.read(), somedict)

2

虽然我来晚了,但我仍然想提供一种替代答案。

如果您想导入代码而不影响全局模块命名空间,可以创建一个匿名模块(使用types.ModuleType),并在其中加载任意代码(使用compileexec)。例如,像这样:

import types

filename = "/path/to/your/file.py"
with open(filename) as fp:
    code = compile(fp.read(), filename, "exec")
config_module = types.ModuleType("<config>")
exec code in config_module.__dict__

您可以使用config_module.var1来访问变量等内容。

Python3 的等价物是什么?我在最后一行遇到了语法错误。 - weberc2

1
如果您想要一个配置文件,只有在程序未运行时才能由用户编辑,只需将其作为普通的Python文件导入即可。
例如:

main.py:

import config
print config.var1

config.py:

var="var12"
var2 = 100.5

我可能有任意数量的配置文件,所以我不能只做一个“import configFile.” 否则这将是最简单的解决方案 :) - Shahbaz

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接