Python 以后手动扩展decorator会使程序崩溃

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 # #

我一直试图从语言的角度理解烧瓶装饰器。根据我对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
#
# 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()