有条件地加载模块Python

che*_*oza 2 python python-2.7

我写了一个主要的python模块,需要加载文件解析器才能工作,最初我只是一个文本解析器模块,但我需要为不同的情况添加更多的解析器.
parser_class1.py
parser_class2.py
parser_class3.py

每个运行实例只需要一个,然后我想通过命令行加载它:

mmain.py -p parser_class1
Run Code Online (Sandbox Code Playgroud)

为此,我编写了这段代码,以便在调用主模块时选择要加载的解析器:

#!/usr/bin/env python

import argparse
aparser = argparse.ArgumentParser()
aparser.add_argument('-p',
            action='store',
            dest='module',
            help='-p module to import')
results = aparser.parse_args()

if not results.module:
    aparser.error('Error! no module')
try:
    exec("import %s" %(results.module))
    print '%s imported done!'%(results.module)
except ImportError, e:
    print e
Run Code Online (Sandbox Code Playgroud)

但是,我正在读这种方式很危险,也许没有标准.

那么,这种方法可以吗?或者我必须找到另一种方法来做到这一点?为什么?谢谢,欢迎任何评论.

Nis*_*n.H 5

你实际上只需import在条件块中执行语句:

if x:
    import module1a as module1
else:
    import module1b as module1
Run Code Online (Sandbox Code Playgroud)

您可以使用此方法以不同方式考虑各种白名单模块导入,但有效的想法是预先编程导入,然后基本上使用GOTO进行正确的导入...如果您确实想让用户导入任何任意参数,那么__import__函数将是要走的路,而不是eval.

更新:

正如@thedox在评论中提到的那样,该as module1部分是用不同底层代码加载类似API的惯用方法.在您打算使用完全不同的API执行完全不同的事情的情况下,这不是要遵循的模式.在这种情况下,更合理的模式是包含与该import语句的特定导入相关的代码:

if ...:
    import module1
    # do some stuff with module1 ...

else:
    import module2
    # do some stuff with module2 ...
Run Code Online (Sandbox Code Playgroud)

至于安全性,如果你允许用户造成一些任意代码设置的进口(如自己的模块,也许?),它并不比使用太大的不同eval的用户输入.它本质上是同一个漏洞:用户可以让你的程序执行自己的代码.

根本不认为让用户导入任意模块是一种真正安全的方式.这里的例外情况是,如果他们无法访问文件系统,因此无法创建要导入的新代码,在这种情况下,您基本上会回到白名单案例,并且还可以实施明确的白名单以防止将来 - 如果/在将来的某个时刻用户确实获得文件系统访问权限的漏洞.

  • 这是一种加载模块的惯用方法,如果它们具有相同的API但不同的内容,如os.path (3认同)