一、前言
在和朋友讨论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这个路由映射表中,这个视图函数就注册成功了。