Как преобразовать строку в функцию в Python?

Мой класс был аннотирован JsonSerialize, а параметр include был установлен на JsonSerialize.Inclusion.NON_DEFAULT. Это заставило Джексона определить значения по умолчанию для каждого свойства bean. У меня было свойство bean, которое возвращало int. Проблема в моем случае заключалась в том, что bean getter обратился к методу, который имеет тип возвращаемого возврата (т. Е. Общий метод). По какой-то нечетной причине этот код скомпилирован; он не должен компилироваться, потому что вы не можете использовать int для типа возвращаемого возврата. Я изменил «int» на «Integer» для этого свойства bean, и у меня больше нет 406. Честно говоря, теперь код не скомпилируется, если я сменил Integer на int.

29
задан dreftymac 16 December 2017 в 19:33
поделиться

9 ответов

Так как вы принимаете пользовательский ввод, самый безопасный способ - точно определить, что является допустимым вводом:

dispatcher={'add':add}
w='add'
try:
    function=dispatcher[w]
except KeyError:
    raise ValueError('invalid input')

Если вы хотите оценивать строки типа 'add(3,4)', вы можете использовать safe eval :

eval('add(3,4)',{'__builtins__':None},dispatcher)

eval в целом может быть опасно при применении к пользовательскому вводу. Вышеуказанное безопаснее, поскольку __builtins__ отключено, а locals ограничено dispatcher. Кто-то умнее, чем я, мог бы по-прежнему вызывать проблемы, но я не мог сказать вам, как это сделать.

ВНИМАНИЕ: Даже eval(..., {'__builtins__':None}, dispatcher) - небезопасно для применения к пользовательскому вводу. Злонамеренный пользователь может запустить произвольные функции на вашем компьютере , если ему будет предоставлена ​​возможность оценить его строку в eval.

42
ответ дан unutbu 16 December 2017 в 19:33
поделиться

Одним из безопасных способов является сопоставление имен и функций. Это безопаснее, чем использовать 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.'
18
ответ дан Chris Morgan 16 December 2017 в 19:33
поделиться

Если вы реализуете подобное оболочке приложение, в котором пользователь вводит какую-то команду (например, , добавляет ), и ответ приложения (возвращает сумму), вы можете использовать модуль 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) help add
add - Добавляет два числа для печати суммы
(Cmd) add 5 3
8
(Cmd) выйти

По приглашению (Cmd) вы можете ввести help команда, которую вы получаете бесплатно. Другими командами являются add и quit, которые соответствуют функциям do_add() и do_quit().

Обратите внимание, что команда help отображает строку документации для вашей функции. Строка документа представляет собой строку, следующую непосредственно за декларацией функции (см., Например, do_add()).

Модуль cmd не разбивает и не разбирает аргументы, поэтому вы должны сделать это самостоятельно. Функция do_add() иллюстрирует это.

Этого примера программы должно быть достаточно, чтобы вы начали. Для получения дополнительной информации просмотрите страницу справки cmd . Это просто настроить подсказку и другие аспекты вашей программы.

5
ответ дан Hai Vu 16 December 2017 в 19:33
поделиться

Просто используйте ссылку на функцию:

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')

Простой и безопасный.

4
ответ дан Jefferson Felix 16 December 2017 в 19:33
поделиться

Встроенная функция eval будет делать то, что вы хотите. Применяются все обычные предупреждения о выполнении произвольного предоставленного пользователем кода.

Если имеется ограниченное количество предопределенных функций, вам следует избегать eval и использовать вместо этого таблицу поиска (т.е. Dict). Никогда не доверяйте своим пользователям.

8
ответ дан Oscar Korz 16 December 2017 в 19:33
поделиться

Решение unutbu - это то, что я обычно использую, но для полноты: злые вещи:

eval("add")(x,y)
10
ответ дан Foo Bah 16 December 2017 в 19:33
поделиться

У меня было много ситуаций, когда мне нужно было сравнить строку с 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
2
ответ дан sidarcy 16 December 2017 в 19:33
поделиться

[Я попал сюда через дублирующий вопрос. Моей первой мыслью было использовать 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()
0
ответ дан 16 December 2017 в 19:33
поделиться

У меня была такая же проблема. способ, которым я рекомендую вам обращаться с этим, состоит в том, чтобы создать временный файл 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])
1
ответ дан Zero Zero 16 December 2017 в 19:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: