从动态文件名导入Python

时间:2018-09-06 08:50:42

标签: python python-3.x

我处于以下情况:我有一个Python脚本main.py,该脚本根据配置文件运行一些操作。配置文件本身就是python脚本/类。我希望能够从命令行传递不同的配置文件作为参数并将其导入主脚本中。

在python中甚至可以动态加载类吗?如果是这样,我如何完成该任务?

请参阅以下最小示例进行澄清。

这是我的脚本main.py

import argparse

def get_arguments():
    parser = argparse.ArgumentParser(description="foo")
    parser.add_argument("--configfile", required=True)
    return parser.parse_args()

def main():
    args = get_arguments()

    from args.configfile import MyConfig # <-- how is that possible?

    if MyConfig.SETTING1:
        do_something()

if __name__ == '__main__':
    main()

这是一个示例config.py

class MyConfig(BaseConfig):
    SETTING1 = True
    SETTING2 = 1 

这是另一个示例config-special.py

class MyConfig(BaseConfig):
    SETTING1 = False
    SETTING2 = 42 

我这样称呼它:

$ python3 main.py --configfile config.py
$ python3 main.py --configfile config-special.py

3 个答案:

答案 0 :(得分:1)

我用这个:

from importlib import import_module
from importlib.util import find_spec

if not find_spec(modulename):
    print('%s: No such module.' % modulename, file=sys.stderr)
    exit(1)

module = import_module(modulename)

try:
    klass = getattr(module, classname)
except AttributeError:
    print('%s: No such class.' % classname, file=sys.stderr)
    exit(1)

如果您的文件不在标准sys.path层次结构中,那么您可能还希望操作PYTHON_PATH

我明确地进行了所有检查(尤其是find_spec),因为如果您只是导入并尝试捕获异常,则很难区分是由于导入失败还是由于导入导致了异常导入的文件内部失败。

答案 1 :(得分:0)

我建议不要使用python文件作为配置。您可以像这样使用configparser方法:

from configparser import ConfigParser
parser = ConfigParser()
parser.read(filename)
if parser.has_section(section):
    items = parser.items(section)

config.ini

[MyBaseSettings]
SETTING1 = True
SETTING2 = 1 

答案 2 :(得分:-1)

使用import_module动态导入模块,详细说明请参见代码。

仍然使用您的下一个命令来调用它们。

$ python3 main.py --configfile config.py
$ python3 main.py --configfile config-special.py

main.py

import argparse
# import sys
from importlib import import_module

def get_arguments():
    parser = argparse.ArgumentParser(description="foo")
    parser.add_argument("--configfile", required=True)
    return parser.parse_args()

def main():
    args = get_arguments()
    module_name = args.configfile[:-3] # here, the result is the file name, e.g. config or config-special

    # Not use __import__, use import_module instead according to @bruno desthuilliers's suggestion
    # __import__(module_name) # here, dynamic load the config module
    # MyConfig = sys.modules[module_name].MyConfig # here, get the MyConfig class
    MyConfig = import_module(module_name).MyConfig

    # from args.configfile import MyConfig # <-- how is that possible?

    if MyConfig.SETTING1:
        #do_something()
        print("do_something")

if __name__ == '__main__':
    main()