flask decorators

今天我们不讲三国,我们好好讲一讲python的decorator(装饰器)
刚开始接触这个概念其实很容易迷惑,我也是从半懂不懂就开始使用,因为flask的例子中总会提到这个route装饰器

@app.route('/')
def index():
    return render_template('index.html')

那么,到底什么是decorator呢? 其实decorator就是一个函数,这个函数接受另外一个函数作为参数,@decorate这种写法这是python提供的语法糖,看下面的例子

@decorate
def target():
    print('running target')

这段代码的意思跟下面这段完全一样

def target():
    print('running target')

target = decorate(target)

但是请记住,这两段代码最后结果中的target已经不是原来的target函数的引用了,而是decorate(target)的引用。可能比较拗口,但是一定要理解。

这里有一个问题,非常重要,就是python什么时候执行decorators

来,下面我们通过代码片段abc.py来看

registry = []
def register(func):
    print('running register(%s)' % func)
    registry.append(func)
    return func

@register
def f1():
    print('running f1')

@register
def f2():
    print('running f2')

def main():
    print('running main')
    print('registry ->', resigtry)
    f1()
    f2()

if __name__ == '__main__'
    main()

保存以上代码,并运行。

python3 abc.py

你可以看到结果是

running register f1
running register f2
running main
registry -> [f1,f2]
running f1
running f2

你可能已经猜到这里面的关键了。

在模块被载入的时候,装饰器就已经执行了。but! 注意这里的but! 被装饰的函数,比如f1,f2是要等到显式的调用才会执行。这里是装饰器的关键。
写到这里,是不是可以大概知道flask中装饰器是怎么起作用的?

@app.route('/')
def index():
    return render_template('index.html')

我们来看一下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

我们来分析一下这个函数。

因为app.route需要接受参数,路由规则是必须的。所以

def route(self, rule, **option)

其实是一个函数工厂,真正的decorator从内部的decorator()函数开始

decorator(f)函数内部有一个函数 add_url_rule

这段代码

@app.route('/')
def index():
    pass

和下面这段代码表达的意思是一样的。

def index():
    pass
app.add_url_rule('/', 'index', index)

也就是decorator(f)内部做的事情,在函数内部调用add_url_rule()

装饰器真的是一个很方便的功能。

End