Python 以后手动扩展decorator会使程序崩溃
我一直试图从语言的角度理解烧瓶装饰器。根据我对decorators的理解,method1、method2和method3应该是相同的Python 以后手动扩展decorator会使程序崩溃,python,flask,gunicorn,Python,Flask,Gunicorn,我一直试图从语言的角度理解烧瓶装饰器。根据我对decorators的理解,method1、method2和method3应该是相同的 # server.py # # callback-based server response, based on official Flask docs: # http://flask.pocoo.org/snippets/8/ # # to run server: # gunicorn server:app --bind localhost:5000 # #
# server.py
#
# callback-based server response, based on official Flask docs:
# http://flask.pocoo.org/snippets/8/
#
# to run server:
# gunicorn server:app --bind localhost:5000
#
# to test:
# curl http://localhost:5000/1 -X POST -d POST_DATA -H "Content-Type: application/json"
# curl http://localhost:5000/2 -X POST -d POST_DATA -H "Content-Type: application/json"
# curl http://localhost:5000/3 -X POST -d POST_DATA -H "Content-Type: application/json"
from flask import Flask, request
app = Flask(__name__)
def callback(*args, **kwargs):
print "post_data=", request.data
return "RESPONSE\n", 200
def wrapper(f):
return callback
# method 1
@app.route('/1', methods=['POST'])
@wrapper
def method1():
pass
# method 2
@app.route("/2", methods=['POST'])
def method2():
return wrapper(method2)
# method 3
@app.route("/3", methods=['POST'])
def method3():
return callback
但是,当我运行3个curl测试时,结果是不同的。在/1和/2的情况下,程序在打印“post_数据=post_数据”后不久崩溃:
请注意,它在完全退出我的app.route方法后死在烧瓶中
一些基础研究表明,其他人遇到了这种“停止迭代”问题:
但在这样一个简单的示例中,或者在任何使用官方flask docs()上的响应回调模式的示例中,都不是这样。因此,我得出结论,问题不在于烧瓶本身,而在于我对装饰师的理解
我不明白这三种方法怎么可能做不同的事情。它们都引用了完全相同的“回调”函数。要么他们成功地将这个函数输入到烧瓶中,要么他们没有
如果他们真的把函数输入烧瓶。。。那么测试就成功了。
如果他们没有将函数输入烧瓶。。。那么Flask究竟是如何调用函数来打印“post_data=post_data”的呢
这种行为似乎完全不合逻辑
(或者我误解了装饰者所做的事情,它实际上是在结果中放入某种隐藏的元数据,而Flask是邪恶的,并以未记录的方式检查元数据。)您的代码有一个基本问题。首先,回想一下一个装饰师
@decorator
def myfunction():
pass
…完全等同于:
def _myfunction():
pass
myfunction = decorator(_myfunction)
记住这一点,您将注意到,在方法2中,您返回的是一个函数,而不是迭代器:
@app.route("/2", methods=['POST'])
def method2():
return wrapper(method2)
请记住,wrapper
的返回值是一个函数:
因此,您在这里有效地做到了:
@app.route("/2", methods=['POST'])
def method2():
return callback
返回的是单个值(函数)而不是元组。你实际上想要:
@app.route("/2", methods=['POST'])
def method2():
return wrapper(method2)()
与方法3类似:
@app.route("/3", methods=['POST'])
def method3():
return callback()
在这两种情况下,您都需要实际调用
回调
函数。否,method1没有调用回调。将断言添加到回调,您将看到它不是从method1调用的。Flask在所有3个方法中都调用了回调。总结一下:装饰器正在做一些让Flask高兴的事情,但它没有调用回调。稍后将通过werkzeug/test模块调用回调。当然,方法1正在调用回调。这就是它工作的原因,也是当您访问/1
时看到响应的原因。我建议删除这些评论,并将它们转移到您的问题中,您可以将它们格式化为可读的格式。注意,我并不是说装饰程序正在调用回调
;请再看一下这个答案(注意这里的代码是有效的)。对不起,你是对的。我看到的是错误的堆栈转储。并且被抛出,因为Flask在所有3种情况下都调用回调(为什么它不打印更有用的错误消息是另一个问题…)。我尝试了很多例子,它的工作方式你说。
@app.route("/2", methods=['POST'])
def method2():
return wrapper(method2)()
@app.route("/3", methods=['POST'])
def method3():
return callback()