我为所有HTTP调用做了一个日志装饰器:
def log_http_call(flask_request_getter: typing.Callable[[], flask.Request]):
def arg_wrapper(wrapped_function):
@wraps(wrapped_function)
def wrapper(*args, **kwargs):
flask_request: flask.Request = flask_request_getter()
print(f'HTTP Method {flask_request.method}: {flask_request.path}')
return wrapped_function(*args, **kwargs)
return wrapper
return arg_wrapper
@app.route('/api/all', methods=['GET'])
@log_http_call(lambda: flask.request)
def get_all():
return "Here you go"
@app.route('/api/<int:_id>/<string:name>', methods=['GET'])
@log_http_call(lambda: flask.request)
def get_one(_id, name):
return f"{name}'s ID is {_id}"
以这种方式工作,但是如果我将装饰器的顺序颠倒为例如:
@log_http_call(lambda: flask.request)
@app.route('/api/all', methods=['GET'])
def get_all():
return "Here you go"
它不再工作。
由于我代码的其他使用者可能以不同的顺序放置这些装饰器,因此我想确保它们以任何一种方式工作。
如何使它以任何顺序工作?
答案 0 :(得分:2)
烧瓶docs特别声明route
装饰器必须位于最外面。除了自己修改Flask库,没有其他方法可以解决这个问题(鉴于开发人员可能很容易做到这一点,这似乎是一项艰巨的任务)。
就像Flask在他们的文档中添加注释一样,您可以在文档中添加类似的注释(或仅引用Flask文档)。
答案 1 :(得分:0)
您不能:装饰器包装一个函数,让多个装饰器包装一个函数中的一个函数。具体来说:than what you'd expect
答案 2 :(得分:0)
执行此操作时:
@app.route('/api/all', methods=['GET'])
@log_http_call(lambda: flask.request)
def get_all():
return "Here you go"
您实际上正在做的是获取内部函数,并将其作为参数传递给包装装饰函数。
本质上,您要求一个f(x)和g(x)使得f(g(x))== g(f(x))。这被称为交换函数合成,并且唯一的情况是f(g(x))== g(f(x))是f(x)是g(x)的倒数。换句话说,装饰器的顺序几乎会100%改变结果。
希望这会有所帮助!