0

我对 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: /

任何见解将不胜感激。

4

2 回答 2

2

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

现在,调用的结果app.route(...)是一个函数,并且因为您已经使用 将@其标记为装饰器,所以该函数将 wrap index。请注意,语法只是一个快捷方式:

index = app.route(...)(index)

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

但是,您在这里缺少一个级别。一个没有参数的普通装饰器是这样写的:

@foo
def bar()
   pass

并且当模块被导入时,foo()运行并返回一个包装bar. 但是你在装饰器调用中调用你的route()函数!所以实际上你的函数需要返回一个装饰器函数,该函数本身返回一个包装原始函数的函数......当然,令人头疼。

您的route方法应该看起来更像这样:

def route(self, *rargs, **kargs):
    args = list(rargs)
    if kargs:
        print(kargs['methods'])
    def decorator(f):
        def wrapped(index_args):
            f(args[0])
        return wrapped
    return decorator
于 2013-09-30T20:30:25.073 回答
-1

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

在您的代码中,当您调用 时index(),它会调用app.route(index, "/", ["GET", "PUT"]). 这从打印开始kargs['methods'],然后创建装饰器函数:

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

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

我发现的装饰器的最佳解释是:如何制作函数装饰器链?

如果你不想自燃,你可以这样定义你的装饰器:

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永远不会使用 index 的参数,因为alwaysroute调用which is always ...indexargs[0]\

于 2013-09-30T20:18:58.237 回答