【问题标题】:How do decorators mark a function?装饰器如何标记功能?
【发布时间】:2026-02-20 20:30:01
【问题描述】:

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

from flask import Flask
app = Flask(__name__)

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

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

我还从许多网站了解了 Python 装饰器的基础知识,包括 * 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()

【问题讨论】:

  • 如果您了解了基础知识,那么您应该知道我们仍然可以使用名称 hello 访问它,因为上面的内容相当于:hello = @app.route("/")(hello)
  • 但要做到这一点,我需要调用 hello(),我没有在 Flask 代码中这样做
  • @KartikAnand 您不必这样做,因为当访问路由 '/' 时,flask 会为您执行此操作。同样,在第二个示例中,当您调用 hello() 时,您实际上是在调用 inner(),而后者又调用了实际的 hello()
  • @AshwiniChaudhary 我理解调用hello() 调用inner() 并依次调用原始hello() 的部分。我不明白的是Flask如何访问hello()内部的原始/

标签: python flask decorator python-decorators


【解决方案1】:

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

【讨论】:

  • 代码中的print 语句是如何工作的?我没有调用任何函数,那么列表是如何填充的?
  • @KartikAnand 你已经调用了decorate 函数;查看编辑。
  • 所以当我装饰一个函数时,它会调用它,因此我可以将它保存在一个列表中!
【解决方案2】:

装饰器实际上是 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

请注意,这几乎是Jon Piparsky provided链接中给出的解释的精简版。

【讨论】:

    【解决方案3】:

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

    其实python中的装饰器

    @some_decorator
    def foo():
        pass
    

    只是一种简写形式

    def foo():
        pass
    
    foo = some_decorator(foo)
    

    函数some_decorator可以用它的参数做任何事情,可以返回任何返回值,但通常返回一个函数。

    【讨论】: