Более элегантный способ вызова произвольных функций Python из Flask

#python #flask

#python #flask

Вопрос:

Настройка REST API Flask проста. Я использую следующий подход:

 from flask import Flask
from flask_cors import CORS

from utility import *

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

@app.after_request
def add_headers(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Headers'] =  "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
    response.headers['Access-Control-Allow-Methods']=  "POST, GET, PUT, DELETE, OPTIONS"
    return response

@app.route("/", methods=["GET"])
def call_function():
    res = request_return()
    return(res)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
 

В этом примере я импортирую функции, находящиеся внутри utility.py:

 from flask import request, jsonify

def my_function(arg):
    return(arg)

def string_to_number(str):
    if("." in str):
        try:
            res = float(str)
        except:
            res = str
    elif(str.isdigit()):
        res = int(str)
    else:
        res = str
    return(res)

def request_return():
    passed_function = request.args.get('function')
    args = dict(request.args)
    values = list(args.values())[1:]
    values = list(map(string_to_number, values))
    res = globals()[passed_function](*tuple(values))
    return(jsonify(res))
 

Это позволяет мне передавать любое имя функции в качестве аргумента и получать результат обратно. Итак, если я запустил следующее в своем браузере:

 https:localhost:5000/?function=my_functionamp;args=hello
 

Я бы увидел:

 "hello"
 

Способ обработки запроса довольно раздут. Вы можете видеть в request_return, что я должен выполнить ряд шагов, чтобы перейти от имени функции к ее выполнению и возврату. Я также использую функцию string_to_number для обработки любых чисел, которые могут быть переданы. Это гарантирует, что я могу вызвать любую функцию внутри утилиты и любое количество параметров для этой функции.

В любом руководстве по Flask, которое я видел, не обсуждается, как вызывать произвольные функции, подобные этому. Есть ли более элегантный способ справиться с этим? В частности, без всех наворотов в моей функции request_return .

Ответ №1:

Разрешать клиенту вызывать любую глобальную функцию опасно, они могут вызвать open() ее для перезаписи файла.

Создайте словарь операций, которые должны быть вызываемыми в вашем приложении.

И вместо того, чтобы пытаться автоматически преобразовывать числа, позвольте отдельным функциям решать, как они хотят анализировать свои аргументы.

 my_operations = {'my_function': my_function, ...}

def request_return():
    passed_function = request.args.get('function')
    try:
        args = dict(request.args)
        del args['function'] # This is processed above
        res = my_operations[passed_function](**args)
        return(jsonify(res))
    except:
        # report error to caller
 

Комментарии:

1. Какие исключения вы получаете?

2. Он принимает 2 позиционных аргумента. Похоже, что «функция» должна быть удалена из аргументов.

3. Я уже добавил это к своему ответу 15 минут назад.

4. Это возвращает «аргументы», а не «привет»

5. Извините, нужно было использовать **args для передачи аргументов по имени.