Как преобразовать строку в функцию в python?
Например, если у меня есть функция, называемая add like
def add(x,y):
return x+y
и я хочу возможность конвертировать строку или вход для прямой к этой функции, например
w=raw_input('Please input the function you want to use')
или
w='add'
Можно ли использовать w для ссылки на функцию add?
Ответы
Ответ 1
Поскольку вы принимаете пользовательский ввод, самым безопасным способом является то, что точно определяет допустимый ввод:
dispatcher={'add':add}
w='add'
try:
function=dispatcher[w]
except KeyError:
raise ValueError('invalid input')
Если вы хотите оценить строки типа 'add(3,4)'
, вы можете использовать безопасный eval:
eval('add(3,4)',{'__builtins__':None},dispatcher)
eval
вообще может быть опасным при применении к пользовательскому вводу. Вышеуказанное безопаснее, так как __builtins__
отключено, а locals
ограничено dispatcher
. Кто-то умнее, чем я мог бы по-прежнему вызывать проблемы, но я не мог сказать вам, как это сделать.
ПРЕДУПРЕЖДЕНИЕ: Даже eval(..., {'__builtins__':None}, dispatcher)
используется небезопасно для ввода пользователя. Злоумышленник может запускать произвольные функции на вашем компьютере, если им предоставляется возможность оценить его строку eval
.
Ответ 2
Один безопасный способ - сопоставить имена с именами. Это безопаснее, чем использование eval
.
function_mappings = {
'add': add,
}
def select_function():
while True:
try:
return function_mappings[raw_input('Please input the function you want to use')]
except KeyError:
print 'Invalid function, try again.'
Ответ 3
unutbu-решение - это то, что я обычно использовал, но для полноты:
Если вы указываете точное имя функции, вы можете использовать eval
, хотя она сильно обескуражена, потому что люди могут делать вредоносные вещи:
eval("add")(x,y)
Ответ 4
Встроенная функция eval
будет делать то, что вы хотите. Все обычные предупреждения о выполнении произвольного кода, поставляемого пользователем, применяются.
Если существует конечное число предопределенных функций, вы должны избегать eval
и вместо этого использовать таблицу поиска (т.е. Dict
). Никогда не доверяйте своим пользователям.
Ответ 5
Если вы реализуете приложение, похожее на оболочку, в котором пользователь вводит какую-то команду (например, add), а приложение отвечает (возвращает сумму), вы можете использовать модуль cmd
, который обрабатывает все взаимодействия команд и диспетчеризацию для вас. Вот пример:
#!/usr/bin/env python
import cmd
import shlex
import sys
class MyCmd(cmd.Cmd):
def do_add(self, arguments):
'''add - Adds two numbers the print the sum'''
x, y = shlex.split(arguments)
x, y = int(x), int(y)
print x + y
def do_quit(self, s):
'''quit - quit the program'''
sys.exit(0)
if __name__ == '__main__':
cmd = MyCmd()
cmd.cmdloop('type help for a list of valid commands')
Вот пример бегущей сессии:
$ python cmd_tryout.py
введите help для получения списка допустимых команд
(Cmd) помогите добавить
add - добавляет два числа к распечатке суммы
(Cmd) добавить 5 3
8
(Cmd) выйти
В командной строке (Cmd) вы можете ввести команду help
которую вы получаете бесплатно. Другими командами являются add
и quit
которые соответствуют do_add()
и do_quit()
.
Обратите внимание, что команда help отображает строку документации для вашей функции. Строка документа представляет собой строку, следующую сразу за объявлением функции (см., do_add()
).
Модуль cmd
не cmd
и не разбирает аргументы, поэтому вы должны сделать это самостоятельно. Функция do_add()
иллюстрирует это.
Этого примера программы должно быть достаточно, чтобы вы начали. Для получения дополнительной информации просмотрите страницу справки cmd. Это пустяки, чтобы настроить подсказку и другие аспекты вашей программы.
Ответ 6
Просто используйте ссылку на функцию:
def pwr(x, y):
return x ** y
def add(x, y):
return x + y
dispatcher = { 'pwr' : pwr, 'add' : add}
def call_func(x, y, func):
try:
return dispatcher[func](x, y)
except:
return "Invalid function"
call_func(2, 3, 'add')
Просто и безопасно.
Ответ 7
У меня было много ситуаций, когда мне нужно было сравнить строку с int и наоборот в шаблоне Django.
Я создал фильтр, который позволил мне передать имя функции и использовать eval() для его преобразования.
Пример:
Шаблон:
{% ifequal string int|convert:'str' %} do something {% endifequal %}
Фильтр шаблонов (где я использую строку для вызова имени функции):
@register.filter
def convert(value, funcname):
try:
converted = eval(funcname)(value)
return converted
except:
return value
Ответ 8
[Я пришел сюда по дублированному вопросу. Моя первая мысль заключалась в использовании argparse
и shlex
, и я не видел этого здесь, поэтому я добавляю его как еще один вариант.]
Вы можете использовать argparse
для настройки реестра функций/команд и безопасного анализа своих аргументов. Это обеспечит некоторый уровень удобства пользователя, например, сообщив вам, когда вы ввели команду, которая не существует.
import argparse
import shlex
def hello(name):
print('hello,', name)
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
hello_parser = subparsers.add_parser('hello')
hello_parser.add_argument('name')
hello_parser.set_defaults(func=hello)
print('Enter q to quit')
while True:
command = input('command> ')
command = command.strip()
if not command:
continue
if command.lower() == 'q':
break
words = shlex.split(command)
try:
args = parser.parse_args(words)
except SystemExit:
# argparse will sys.exit() on -h and errors; prevent that
continue
func_args = {name: value for name, value in vars(args).items()}
del func_args['func']
args.func(**func_args)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print()
Ответ 9
У меня такая же проблема. способ, которым я рекомендую вам обращаться с этим, состоит в том, чтобы создать временный файл Python для хранения функции, введенной пользователем. Вот пример, который я использовал в программе, которую я написал, чтобы нарисовать представление математических функций:
with open("function.py",'w') as file:
f=input('enter the funtion you want to draw example: 2*x+1 or e**x :\n')
file.write("from math import *\ndef f(x):\n\treturn "+f)
это создаст файл, содержащий функцию, которую я хочу вызвать следующим, вы должны вызвать функцию, которую вы написали в файле для вашей программы:
from function import f
Теперь вы можете использовать свою функцию как обычную функцию Python, если хотите, вы также можете удалить файл, в котором вы сохранили свою функцию, используя os.remove:
import os
os.remove("function.py")
Чтобы помочь вам понять, вот моя программа для рисования математических функций:
import numpy
import cv2
import os
from math import *
def generate(f,a,b,min,max,functionname='noname'):
ph=(b-a)/1920
pv=(max-min)/1080
picture=numpy.zeros((1080,1920))
for i in range(0,1920):
picture[1079-(int((f(a+(i+1)*ph)*1080/max))),i]=255
for i in range(1920):
picture[1079-(int((f(a+(i+1)*ph)*1080/max)))+1,i]=255
cv2.imwrite(functionname+'.png',picture)
with open("function.py",'w') as file:
f=input('enter the funtion you want to draw example: or e**x :\n')
file.write("from math import *\ndef f(x):\n\treturn "+f)
from function import f
os.remove("function.py")
d=input('enter the interval ,min ,max and the image file name. Separate characters with spacebar. Example: 0 1 0 14 exponontielle :\n').split(" ")
generate(f,int(d[0]),int(d[1]),int(d[2]),int(d[3]),d[4])