問(wèn)題
Flask中的app實(shí)例是一個(gè)很重要的單例,當(dāng)我們?cè)谧鲆晥D函數(shù)拆分的時(shí)候,如果不做考慮,很容易造成循環(huán)引入的問(wèn)題。
比如說(shuō)我們?cè)趯慺lask應(yīng)用的時(shí)候,要把a(bǔ)pp.py中的視圖函數(shù)提取到另一個(gè)py文件,而在視圖函數(shù)中注冊(cè)路由時(shí)需要app的實(shí)例,因此就會(huì)導(dǎo)入app.py中的app實(shí)例,而為了能夠完成路由的注冊(cè),app.py 需要導(dǎo)入視圖函數(shù)的模塊,這個(gè)時(shí)候就形成了一個(gè)循環(huán)引用。
# app.py
from flask import Flask
app = Flask(__name__) # 實(shí)例化一個(gè)Flask對(duì)象
import admin # 這里導(dǎo)入admin是為了完成admin.py中路由的注冊(cè)
if __name__ == '__main__':
app.run()
# admin.py
from app import app # 為了注冊(cè)路由,需要導(dǎo)入app.py中的app實(shí)例
@app.route('/admin')
def index():
return 'hello world!'
這時(shí)候如果運(yùn)行app.py發(fā)現(xiàn)什么錯(cuò)誤都不會(huì)報(bào),但是訪問(wèn)/admin時(shí)候,會(huì)發(fā)現(xiàn)404錯(cuò)誤,找不到路由。
為什么會(huì)這樣呢。
代碼分析
輸出 app 實(shí)例的 id 來(lái)看一下就明白了。
# app.py
from flask import Flask
app = Flask(__name__) # 實(shí)例化一個(gè)Flask對(duì)象
print('id為{}的app實(shí)例化'.format(id(app)))
import admin # 這里導(dǎo)入admin是為了完成admin.py中路由的注冊(cè)
if __name__ == '__main__':
print('id為{}的app啟動(dòng)'.format(id(app)))
app.run()
# admin.py
from run import app
print('id為{}的app注冊(cè)路由'.format(id(app)))
@app.route('/admin')
def index():
return 'hello world'
運(yùn)行一下,結(jié)果如下:
id為2052896477592的app實(shí)例化
id為2050881952288的app實(shí)例化
id為2050881952288的app注冊(cè)路由
id為2052896477592的app啟動(dòng)
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
可以看到 app 被實(shí)例化了兩次,而且注冊(cè)路由的 app 和最終啟動(dòng)的 app 不是同一個(gè) app 實(shí)例,所以會(huì)出現(xiàn)404。
為什么會(huì)執(zhí)行兩次呢。下面用圖表示一下運(yùn)行過(guò)程。
流程圖分析

首先程序從app.py中運(yùn)行,執(zhí)行到import admin 時(shí),會(huì)進(jìn)入admin文件,當(dāng)在admin文件中再次調(diào)用app時(shí),又返回到app.py文件中運(yùn)行,但是python不會(huì)重復(fù)循環(huán)導(dǎo)入,所以第二次的時(shí)候就不會(huì)再次進(jìn)入admin文件中,便向下執(zhí)行if語(yǔ)句,此時(shí)的app.py文件是被admin.py文件調(diào)用的,所以此時(shí)的__name__ != __main__,所以不會(huì)運(yùn)行app.run()方法,執(zhí)行完app.py文件時(shí),便會(huì)回到admin中繼續(xù)執(zhí)行app route,調(diào)用完成后回到app中,繼續(xù)執(zhí)行,此時(shí)的app實(shí)例才是app.py中的,所以會(huì)執(zhí)行run。
解決方法
解決循環(huán)導(dǎo)入的方法有很多種方式,在Flask中通常使用藍(lán)圖來(lái)實(shí)現(xiàn)模塊化,解決循環(huán)導(dǎo)入的問(wèn)題。
藍(lán)圖的使用