Предполагая, что вы на самом деле хотите принять произвольный код Python в качестве пользовательского ввода и запустить его, чего вы обычно действительно не хотите делать, но давайте предположим, что у вас есть веская причина ...
Ново-первых: вы упомянули попытки сделать это с SymPy.Если вы на самом деле пытаетесь создать функции из выражений SymPy, например, используя sympify
или lambdify
- это должно сработать, а если это не так, вам нужно показать нам свой код, если вы хотите помочь в отладкеэто.
Но давайте прекратим останавливаться и перейдем к тому, как вы можете делать то, что вы просили, даже если есть большая вероятность, что на самом деле это не то, что вы хотите.
Помните, чтоДекораторы - это просто функции, которые принимают функцию и возвращают другую функцию, и вы можете вызывать их как обычно.Итак, все, что вам нужно сделать, это превратить этот произвольный код 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}'))
Если выВы думаете: «Но подождите, eval
опасно» - ну, да, 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)