装饰函数如何在flask / python中工作? (app.route)

时间:2017-09-08 19:33:15

标签: python flask decorator

编辑2:我误解了装饰器是如何工作的。即使未调用装饰函数(即使您可能看不到它的效果),装饰器也会运行。 function = dec(function)将是一个显示装饰器功能的等效方式,显然在这种情况下,dec()函数在没有调用function()的情况下运行。

编辑:为什么我的帖子被拒绝投票而没有解释?我该如何解决?有多个答案,一个清楚地回答了这个问题。有什么问题?

我一直在学习python中的装饰器,我想我对它们有很好的把握。但是我仍然对app.route装饰器如何在烧瓶中工作感到有些困惑。根据我的理解,装饰器会更改函数的行为,但除非调用该函数,否则不会运行。如果我有:

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

hello()

hello函数将传递给app.route,并且装饰器指令将执行的任何行为。但是在烧瓶应用程序中,函数本身似乎永远不会运行(在上面的示例中它是)。如果它的装饰函数从未被调用,那么route function / decorator是如何执行的?我知道app.route基本上存储" /"以及它在字典中的相应功能,但我不理解如何在没有任何调用装饰函数的情况下执行此代码。我假设它在某种程度上连接到了烧瓶应用程序结束时的app.run,但我不清楚app.run如何调用你定义的函数。

编辑:添加到我在此处显示的内容。这个解释有一个例子:https://ains.co/blog/things-which-arent-magic-flask-part-1.html提出了同样的问题。我认为需要调用hello()才能让route函数做任何事情。

class NotFlask():
    def __init__(self):
        self.routes = {}

    def route(self, route_str):
        def decorator(f):
            self.routes[route_str] = f
            return f

        return decorator

    def serve(self, path):
        view_function = self.routes.get(path)
        if view_function:
            return view_function()
        else:
            raise ValueError('Route "{}"" has not been 
registered'.format(path))


app = NotFlask()

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

2 个答案:

答案 0 :(得分:10)

像这样的Python装饰器:

@decorator
def func():
    pass

可以改为看起来像这样:

def func():
    pass

decorator(func)

或者换句话说,它们是具有功能的功能。在某些情况下,您可能不会立即看到装饰器的效果,因此看起来装饰器本身在调用它所装饰的函数之前不会被使用,但这不是Python装饰器的实际限制。

在您的代码中,@app.route("/")是一个装饰器,它将一个端点添加到app对象。它实际上并没有修改函数的任何行为,而是简化了过程。如果没有route()装饰器,这就是你在Flask中进行等效路径注册的方法。

from flask import Flask
app = Flask(_name_)

def hello():
    return "Hello world"

app.add_url_rule("/", "hello", hello)

如果您查看Flask中的implementation of the route decorator,您会发现这是等效的。

def route(self, rule, **options):
        """A decorator that is used to register a view function for a
        given URL rule.  This does the same thing as :meth:`add_url_rule`
        but is intended for decorator usage::
            @app.route('/')
            def index():
                return 'Hello World'
        For more information refer to :ref:`url-route-registrations`.
        :param rule: the URL rule as string
        :param endpoint: the endpoint for the registered URL rule.  Flask
                         itself assumes the name of the view function as
                         endpoint
        :param options: the options to be forwarded to the underlying
                        :class:`~werkzeug.routing.Rule` object.  A change
                        to Werkzeug is handling of method options.  methods
                        is a list of methods this rule should be limited
                        to (``GET``, ``POST`` etc.).  By default a rule
                        just listens for ``GET`` (and implicitly ``HEAD``).
                        Starting with Flask 0.6, ``OPTIONS`` is implicitly
                        added and handled by the standard request handling.
        """
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

因此,您可以看到route将其添加到应用程序的路由器,因此一旦Flask应用程序收到请求,它就会决定如何为已请求的端点执行代码/视图。

答案 1 :(得分:0)

您的代码段直接调用hello函数。这就是函数运行的原因。

对于Flask,您可以使用装饰器函数定义路径。当您导航到与装饰器匹配的URL时,它将执行装饰的功能。在此示例中,如果我在我的网络服务器上导航到“/”,则hello功能将执行。

要实际运行服务器,您需要从命令行执行以下操作(也可以在Flask's documentation中找到。

$ export FLASK_APP=hello.py
$ flask run

其中hello.py是包含Python代码的文件的名称。您还应该删除文件中hello()的直接电话。然后打开浏览器并导航到http://localhost:5000/以查看结果。

装饰器如何工作

装饰器是包含其他函数以试图改变子函数行为的函数。您可以阅读Python wiki中的详细说明。

装饰者接受一个函数作为他们的参数。通常,装饰器在执行子功能之前运行一些代码。例如,如果要将身份验证添加到Flask应用程序的某些端点,则可以使用装饰器。装饰器检查以确保用户在该资源的实际代码执行之前经过身份验证以使用资源。

@authenticate
def hello():
   return "Hello world"

authenticate函数将首先运行。然后,如果用户通过身份验证,它将调用hello执行其余操作,否则,它将向用户发送错误。对于Flask的装饰器,他们正在检查传入的请求是否与您指定的路径匹配。如果是,则执行该功能。否则,它会检查下一条路线。

以下文章是关于装饰器的学习:https://realpython.com/blog/python/primer-on-python-decorators/