flask路由
在使用flask時,我們設(shè)置路由的方式通常為:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '1'
@app.route('/test')
def test():
return '2'
if __name__ == '__main__':
print(app.url_map)
問題來了, 我們并沒有執(zhí)行定義的函數(shù),那么app.route()方法是如何將我們的url和視圖函數(shù)象關(guān)聯(lián)并打印出url_map的呢?
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
從源碼可以發(fā)現(xiàn),route的本質(zhì)是一個裝飾器,再route方法被觸發(fā)后,進一步調(diào)用add_url_rule來注冊我們設(shè)定的url。
裝飾器
在開始的代碼中,我們并沒有調(diào)用相關(guān)的視圖函數(shù),如index(), 那么裝飾器為什么還會被觸發(fā)呢?
裝飾器的作用大家應(yīng)該都很清楚: 在不改變原有代碼結(jié)構(gòu)的基礎(chǔ)上對函數(shù)進行一次封裝,添加特定的功能。來看一個例子:
import time
def log(f):
def decorator():
t1 = time.time()
f()
t2 = time.time()
print('time: {}'.format(t2-t1))
return decorator
@log
def test():
time.sleep(2)
print('test')
if __name__ == '__main__':
test()
'''
結(jié)果:
test
time: 2.0009994506835938
'''
這個例子很常見,功能是在函數(shù)執(zhí)行后打印該函數(shù)的執(zhí)行時間。其實,在代碼執(zhí)行到@log時,python執(zhí)行了下面一句代碼: test = log(test) 這句代碼返回decorator函數(shù)。讓我們驗證一下:
import time
def log(f):
def decorator():
t1 = time.time()
f()
t2 = time.time()
print('time: {}'.format(t2-t1))
print('log....')
return decorator
@log
def test():
time.sleep(2)
print('test')
if __name__ == '__main__':
pass
'''
結(jié)果:
log....
'''
明白了這一點,回到開始時的route方法:
@app.route('/')
def index():
return '1'
這段代碼發(fā)生了什么?其實,它的調(diào)用過程為:index = app.route('/')(index)
route函數(shù)接收rule和關(guān)鍵字參數(shù)**options, rule的值為‘/’,執(zhí)行后返回decorator,decorator接收一個參數(shù)f,值為index。route函數(shù)通過調(diào)用add_url_rule方法將Rule類的實例,加入到url_map中去。