Flask中的循环导入

问题

Flask中的app实例是一个很重要的单例,当我们在做视图函数拆分的时候,如果不做考虑,很容易造成循环引入的问题。

比如说我们在写flask应用的时候,要把app.py中的视图函数提取到另一个py文件,而在视图函数中注册路由时需要app的实例,因此就会导入app.py中的app实例,而为了能够完成路由的注册,app.py 需要导入视图函数的模块,这个时候就形成了一个循环引用。

# app.py
from flask import Flask

app = Flask(__name__) # 实例化一个Flask对象

import admin # 这里导入admin是为了完成admin.py中路由的注册

if __name__ == '__main__':
    app.run()
# admin.py
from app import app # 为了注册路由,需要导入app.py中的app实例

@app.route('/admin')  
def index():
    return 'hello world!'

这时候如果运行app.py发现什么错误都不会报,但是访问/admin时候,会发现404错误,找不到路由。
为什么会这样呢。

代码分析

输出 app 实例的 id 来看一下就明白了。

# app.py
from flask import Flask

app = Flask(__name__) # 实例化一个Flask对象
print('id为{}的app实例化'.format(id(app)))
import admin # 这里导入admin是为了完成admin.py中路由的注册

if __name__ == '__main__':
    print('id为{}的app启动'.format(id(app)))
    app.run()
# admin.py
from run import app

print('id为{}的app注册路由'.format(id(app)))


@app.route('/admin')
def index():
    return 'hello world'

运行一下,结果如下:

id为2052896477592的app实例化
id为2050881952288的app实例化
id为2050881952288的app注册路由
id为2052896477592的app启动
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

可以看到 app 被实例化了两次,而且注册路由的 app 和最终启动的 app 不是同一个 app 实例,所以会出现404。
为什么会执行两次呢。下面用图表示一下运行过程。

流程图分析


首先程序从app.py中运行,执行到import admin 时,会进入admin文件,当在admin文件中再次调用app时,又返回到app.py文件中运行,但是python不会重复循环导入,所以第二次的时候就不会再次进入admin文件中,便向下执行if语句,此时的app.py文件是被admin.py文件调用的,所以此时的__name__ != __main__,所以不会运行app.run()方法,执行完app.py文件时,便会回到admin中继续执行app route,调用完成后回到app中,继续执行,此时的app实例才是app.py中的,所以会执行run。

解决方法

解决循环导入的方法有很多种方式,在Flask中通常使用蓝图来实现模块化,解决循环导入的问题。
蓝图的使用

你可能感兴趣的:(Flask中的循环导入)