在阅读了关于处理配置文件的Software Carpentry文章后,我对他们的方法 #5 感兴趣:将参数放入动态加载的代码模块中。基本上我希望能够在我的输入文件中进行计算以创建我的变量。
基于this SO answer for how to import a string as a module 我编写了以下函数来将字符串或oen文件对象或STringIO作为模块导入。然后我可以使用 . 操作员:
import imp
def make_module_from_text(reader):
"""make a module from file,StringIO, text etc
Parameters
----------
reader : file_like object
object to get text from
Returns
-------
m: module
text as module
"""
#for making module out of strings/files see https://stackoverflow.com/a/7548190/2530083
mymodule = imp.new_module('mymodule') #may need to randomise the name; not sure
exec reader in mymodule.__dict__
return mymodule
然后
import textwrap
reader = textwrap.dedent("""\
import numpy as np
a = np.array([0,4,6,7], dtype=float)
a_normalise = a/a[-1]
""")
mymod = make_module_from_text(reader)
print(mymod.a_normalise)
给
[ 0. 0.57142857 0.85714286 1. ]
到目前为止一切都很好,但是环顾四周似乎使用 pythoneval
并且exec
如果我不信任输入会引入安全漏洞。一个常见的回答是“永远不要使用eval or
exec;它们是邪恶的”,但我真的很喜欢执行代码的强大功能和灵活性。使用{'__builtins__': None}
我不认为对我有用,因为我想导入其他模块(例如import numpy as np
在我上面的代码中)。许多人(例如这里)建议使用该ast
模块,但我完全不清楚如何使用它(可以ast
与exec
?一起使用)。是否有简单的方法来白名单/允许特定功能(例如这里)? 是否有简单的方法将特定功能列入黑名单/禁止?有没有一种神奇的方式可以说执行这个但不要做任何讨厌的事情。
基本上有哪些选项可以确保exec
不运行任何讨厌的恶意代码?
编辑:
我上面关于在我的输入/配置文件中规范化数组的示例对于我想要在我的输入/配置文件中执行的计算可能有点简单(我可以很容易地在我的程序中编写一个方法/函数来做到这一点)。但是假设我的程序在不同时间计算一个属性。用户需要以某种方式指定时间。我是否应该只接受一个明确的时间值列表,以便用户在准备输入文件之前必须进行一些计算?(注意:即使使用列表作为配置变量也不是微不足道的,请参见此处)。我认为这是非常有限的。我应该允许 start-end-step 值然后numpy.linspace
在我的程序中使用吗?我认为这也有限制;如果我想用怎么办numpy.logspace
反而?如果我有一些函数可以接受重要时间值的列表,然后很好地填充其他时间以获得间隔时间值。用户能够导入该功能并使用它不是很好吗?如果我想输入用户定义的对象列表怎么办?问题是,当我和我的用户已经可以使用 python 的功能时,我不想为所有这些特定情况编写代码。一旦我接受我确实想要在我的输入/配置文件中执行代码的能力和功能,我想知道在使用exec
vs using importlib
vs imp.load_source是否真的有任何区别,安全方面等等。对我来说,有有限的标准 configparser 或全能、全危险的 exec。我只是希望有一些中间立场,我可以说'执行这个......而不用填满我的电脑'。