装饰器如何标记一个函数?

How do decorators mark a function?

我正在阅读具有以下代码的基本 Flask 教程:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

我还从许多网站上学习了 Python 装饰器的基础知识,包括 Whosebug Decorators

我假设在前面的代码中,函数 hello 将被更改和修饰,对于 运行 应用程序,我需要在某处调用函数 hello() . Flask 如何确定它必须调用的函数的名称。

仅仅用装饰器包装函数定义是否以某种方式标记了该函数?如果是,怎么做?

例如,在下面的代码中,我正在调用我修饰过的函数的某处:

def decorate(foo):
    print("I'm doing a lot of important stuff right now")

    def inner():
        print("Some stuff 1")
        foo()
        print("Some stuff 2")

    return inner

@decorate
def hello():
    print("Hello")

hello()

decorate中,foo是你正在装饰的函数(在本例中,hello)。您可以将该函数存储在某处的列表或字典中,因为它是一个普通对象。

例如:

decorated_functions = []

def decorate(foo):
    def inner():
        print("Some stuff 1")
        foo()
        print("Some stuff 2")

    decorated_functions.append(inner)
    return inner

@decorate
def hello():
    print("Hello")

## The above is the same as:
# def hello():
#     print("Hello")
# hello = decorate(hello)

print(decorated_functions[0] == hello) # prints True
decorated_functions[0]() # prints "Some stuff 1", "Hello", and "Some stuff 2"
hello() # same as above

装饰器实际上是 Python 中的一个非常简单的结构。下面两个例子是等价的:

@foo
def bar():
     pass

def bar():
     pass

bar = foo(bar)

因此您在第一个示例中对 hello 的定义等同于:

def hello():
     return "Hello World!"

hello = app.route("/")(hello)

双函数调用可能有点混乱,所以让我们重写如下:

_tempfn = app.route("/")
hello = _tempfn(hello)

所以现在应该清楚 app.route 实际上不是装饰器,它是 创建 装饰器的函数。现在不明显的是新装饰器做了什么。如果不查看 Flash 的源代码,它可能会将函数 hello 添加到 app 的字典成员中。所以 app.route 是这样实现的:

class app(object):
    def route(self, path):
        def decorator(fn):
            self.pathmap[path] = fn
            return fn
        return decorator

请注意,这几乎是 link Jon Piparsky provided.

中给出的解释的浓缩版

装饰器只是在查找中注册函数 table。装饰器不需要以任何方式修改函数,装饰器可以做很多其他有用的事情。

事实上,python

中的装饰器
@some_decorator
def foo():
    pass

只是

的缩写形式
def foo():
    pass

foo = some_decorator(foo)

和函数 some_decorator 可以用它的参数做任何事情,并且可以 return 任何 return 值,但通常 return 是一个函数。