在用户输入字符串上使用numba.jit

时间:2018-06-01 00:09:13

标签: python numba

我正在尝试编写一个程序,它将用户输入函数作为字符串,并使用该函数进行大量计算。这些计算是使用numba.jit完成的,如果我对我的函数进行硬编码,代码就可以工作,但是我无法弄清楚如何解析字符串,以便我可以将它转换为带有nopython = True的jitted函数。

例如,我的代码使用函数

运行
@jit(nopython=True)
def f(x):
    return x*x

但我希望将用户输入字符串'x * x'设置为创建相同的函数。我已经尝试过使用SymPy,但是我无法让它与jit很好地配合使用。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

假设你真的想把任意Python代码作为用户输入并运行它 - 你通常真的,真的不想做,但让我们假设你有充分的理由... < / p>

但首先:你提到过试图用SymPy做这件事。如果您实际上尝试使用SymPy表达式创建函数,例如,使用sympifylambdify - 这应该有效,如果它不起作用,则需要显示如果您需要帮助调试它,请使用您的代码。

但是,让我们停止拖延并了解你如何做你所要求的,尽管它很有可能它实际上并不是你想要的。

请记住,装饰器只是函数,它接受一个函数并返回另一个函数,你可以正常调用它们。因此,您所要做的就是将任意Python代码转换为函数,然后将其传递给装饰器。

如果任意Python代码只是一个表达式,你可以将它包装在lambda表达式中,eval结果,并且你有一个应用该表达式的函数:

lambdastr = f'lambda x: {user_string}'
lambdafunc = eval(lambdastr)
numbafunc = numba.jit(nopython=True)(lambdafunc)

或者,如果您愿意:

numbafunc = numba.jit(nopython=True)(eval(f'lambda x: {user_string}'))

如果您正在思考&#34;但是等等,eval很危险&#34; -well,是的,eval是危险的,因为它会将任意用户字符串作为代码进行评估,这是正是你想要做的。没有非危险的方法可以做到这一点。

因此,如果您的用户将字符串x * x传给您,您现在已经获得了一个对其输入进行平方的功能,如果用户将字符串__import__('os').system('rm -rf /')传递给您,您就可以了。我现在有一个功能,试图擦除你的整个硬盘。

如果你想发表一个声明,你可以通过将其包裹在def并调用exec来有效地做同样的事情:

defstr = f'def __(x): {user_string}'
deffunc = exec(defstr)
numbafunc = numba.jit(nopython=True)(deffunc)

如果任意Python代码可以是一个语句块,那么由于你需要处理缩进这一点会稍微复杂一些,但这并不太难:

user_lines = '\n'.join(' '+line for line in user_string.splitlines())
defstr = f'def __(x):\n{user_lines}'
deffunc = exec(defstr)
numbafunc = numba.jit(nopython=True)(deffunc)