Python装饰器自我解雇

时间:2013-09-30 20:11:42

标签: python python-decorators

我对Python很新,并且一直在学习装饰器。在搞乱Flask之后,我正在尝试编写一些模拟其路由处理程序/装饰器的代码,只是为了理解装饰器(带参数)是如何工作的。

在下面的代码中,路径装饰器似乎在脚本运行后调用自身。我的问题是,当我运行这个脚本时,app.route()怎么可能被调用,这里真的发生了什么?请注意,我不会直接在任何地方调用index()函数。

# test.py

class Flask(object):

    def __init__(self, name):
        self.scriptname = name

    def route(self, *rargs, **kargs):
        args = list(rargs)
        if kargs:
            print(kargs['methods'])
        def decorator(f):
            f(args[0])
        return decorator

app = Flask(__name__)

@app.route("/", methods = ["GET","PUT"])
def index(rt):
    print('route: ' + rt)

以上在我的终端中打印出来:

$ python test.py
['GET', 'PUT']
route: /

任何见解都将受到赞赏。

2 个答案:

答案 0 :(得分:2)

@app.route("/", methods = ["GET","PUT"])是一个可执行语句:它调用app对象的route()方法。由于它是在模块级别,因此将在导入脚本时执行。

现在,调用app.route(...)结果是一个函数,因为你已经使用@将它标记为装饰器,该函数将包装{{ 1}}。请注意,语法只是一个快捷方式:

index

换句话说,Python将index = app.route(...)(index) 返回的函数作为参数调用,并将结果存储为新的app.route()函数。

然而,你在这里错过了一个级别。没有params的普通装饰器是这样写的:

index

并且导入模块时,运行index并返回包装@foo def bar() pass 的函数。但是你在装饰者的电话中调用你的foo()函数 !所以实际上你的函数需要返回一个装饰器函数,它本身返回一个包装原始函数的函数... headscratching,确定。

您的bar方法应该更像这样:

route()

答案 1 :(得分:-1)

基本上...... app.route(index, "/", ["GET", "PUT"])是一个功能。这是将被调用而不是索引的函数。

在您的代码中,当您致电index()时,它会调用app.route(index, "/", ["GET", "PUT"])。首先打印kargs['methods'],然后创建装饰器功能:

def decorator(f):
    f(args[0])

此装饰器将使用一个参数f调用装饰函数(args[0]),此处为“/”。这会打印route: /

我找到的装饰者的最佳解释是:How to make a chain of function decorators?

如果您不想自我解雇,可以这样定义装饰器:

def route(*rargs, **kargs):
    args = list(rargs)
    if kargs:
        print(kargs['methods'])
    def decorator(f):
        f(args[0])
    return decorator

@app.route("/", methods = ["GET","PUT"])
def index(rt):
    print('route: ' + rt)

但是,永远不会使用索引的rt参数,因为route始终使用index调用args[0]\始终为{{1}} ... < / p>