flask的视图装饰器起到的作用以及源码流程

一、前言

在和朋友讨论flask的装饰器时,产生了这个装饰器为什么能够让flask知道有这个视图函数呢?所以,我就扒开了源码,来看看它是怎么实现的。

二、先了解一下装饰器

装饰器是为了给函数添加附加功能
实现装饰器,有两个原则:
1.不修改被修饰函数的源代码
2.不修改被修饰函数的调用方式

来看一个简单的装饰器:


# def out(name):
#     def decor(function):
#         def inner():
#             function()
#             if name == '屌丝':
#                 print('在洗澡')
#             elif name == '高富帅':
#                 print('好无聊呀,你陪我聊会天吧')
#         return inner
#     return decor
#
# @out('屌丝')  #相当于  sell = out('屌丝')(sell)
# def  sell():
#     print('lala')
# sell()

注意:@out(‘屌丝’) #相当于 sell = out(‘屌丝’)(sell)

具体的装饰器理解,这里不再累述。让我们进入flask源码

三、flask的路由注册

@app.route('/index',methods=['POST','GET']) # index =  route('/index')(index)
def index():
    pass

同理,flask中的装饰器也是一样的,@app.route(’/index’,methods=[‘POST’,‘GET’])是等价于# index = route(’/index’)(index)的

进入flask源码route()函数,具体代码如下:

 def route(self, rule, **options): 
      
        def decorator(f):  
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

参数rule就是匹配路由’/index’,**options接收的是[‘POST’,‘GET’],那么decorator(f)中的f就是index这个函数,不理解看装饰器部分。

我们接着执行,endpoint = options.pop(“endpoint”, None),得到endpoint = None,
执行self.add_url_rule(rule, endpoint, f, **options),进入add_url_rule函数,

    def add_url_rule(
        self,
        rule,
        endpoint=None,
        view_func=None,
        provide_automatic_options=None,
        **options
    ):
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options["endpoint"] = endpoint
        methods = options.pop("methods", None)

        # if the methods are not given and the view_func object knows its
        # methods we can use that instead.  If neither exists, we go with
        # a tuple of only ``GET`` as default.
        if methods is None:
            methods = getattr(view_func, "methods", None) or ("GET",)
        if isinstance(methods, string_types):
            raise TypeError(
                "Allowed methods have to be iterables of strings, "
                'for example: @app.route(..., methods=["POST"])'
            )
        methods = set(item.upper() for item in methods)

        # Methods that should always be added
        required_methods = set(getattr(view_func, "required_methods", ()))

        # starting with Flask 0.8 the view_func object can disable and
        # force-enable the automatic options handling.
        if provide_automatic_options is None:
            provide_automatic_options = getattr(
                view_func, "provide_automatic_options", None
            )

        if provide_automatic_options is None:
            if "OPTIONS" not in methods:
                provide_automatic_options = True
                required_methods.add("OPTIONS")
            else:
                provide_automatic_options = False

        # Add the required methods now.
        methods |= required_methods

        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an "
                    "existing endpoint function: %s" % endpoint
                )
            self.view_functions[endpoint] = view_func

开始执行第一句if endpoint is None:,满足条件,执行
endpoint = _endpoint_from_view_func(view_func),
进入_endpoint_from_view_func,具体源代码如下:

def _endpoint_from_view_func(view_func):
    """Internal helper that returns the default endpoint for a given
    function.  This always is the function name.
    """
    assert view_func is not None, "expected view func if endpoint is not provided."
    return view_func.__name__

我们知道,view_func = index这个函数,断言成功,返回这个函数名index,
返回到add_url_rule方法中,得到endpoint = index (index是一个函数名),
再执行methods = getattr(view_func, “methods”, None) or (“GET”,)
getattr(view_func, “methods”, None) = None,所以methods = (“GET”,)

继续向下走,我们看到self.url_map.add(rule),结果就出来了,
再这里,把rule添加到了url_map这个路由映射表中,这个视图函数就注册成功了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值