bigywater.tech
Flask · 70

Application Factory

为什么都说要用 create_app()?它解决了什么问题?扩展怎么配合?命令行与 gunicorn 怎么找到它?这篇先复现没有工厂的麻烦,再逐项验证工厂模式。

ImportError
没有工厂、顶部互相导入时的循环导入错误
3 个
本篇用同一个工厂创建的、配置各不相同的实例数
305 µs
create_app() 一次的耗时(1 蓝图 + 1 扩展)

没有工厂的问题

实测 · 本机执行输出
  视图模块在顶部写 from bad.app import app,应用模块又在顶部 from bad import views → ImportError: cannot import name 'app' from partially initialized module 'bad.app'
  常见的绕法:把 from bad2 import views 放到 app.py 的末尾。导入 bad2.app 时路由已注册: ['/']
  整个进程里只有一个 app 实例,config["NAME"] = 全局唯一 | 再导入一次得到的是同一个对象: True (想要两套不同配置的实例:做不到)

上一篇:Development、Testing、Production 配置;下一篇:Extension 初始化时机。

多个隔离的实例

实测 · 本机执行输出
  三个实例: ['app-one', 'app-two', 'default'] | 互不相同: True
  各自的响应: [{'ext': {'name': 'app-one'}, 'name': 'app-one'}, {'ext': {'name': 'app-two'}, 'name': 'app-two'}]
  EXTRA 只在 a2 的配置里: [False, True, False]
  各自的路由表独立: [2, 2, 2]

扩展与 init_app

实测 · 本机执行输出
  同一个 db_like 对象先后被绑定到的应用: ['app-one', 'app-two', 'default']
  每个应用自己的 extensions 字典: [{'name': 'app-one'}, {'name': 'app-two'}, {'name': 'default'}]

current_app

实测 · 本机执行输出
  views.py 里 import 了 app 吗? False | 用 current_app: True
  在应用上下文之外访问 current_app → RuntimeError: Working outside of application context.
  with a2.app_context(): current_app.config["NAME"] = app-two

命令行与 gunicorn

实测 · 本机执行输出
  flask --app good(自动发现 create_app)                → 退出码 0 
  flask --app "good:create_app()"                  → 退出码 0 
  flask --app "good:create_app({'NAME': 'cli'})"   → 退出码 0 
  flask --app mod_app(模块里有 app 变量)                 → 退出码 0 
  flask --app mod_app:make_app                     → 退出码 0 
  flask --app nope                                 → 退出码 2 Error: Could not import 'nope'.
  gunicorn "good:create_app()" → GET / → {"ext":{"name":"default"},"name":"default"}

创建耗时

实测 · 本机执行输出
  create_app(...) 每次 305 µs

分步演示

Application Factory
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:大型项目里工厂的启动耗时构成、Celery 等后台进程里调用工厂的方式、工厂里创建的线程池或连接在多 worker fork 之后的表现(见第 145 篇)、flask --app 对带复杂参数工厂的解析限制
    京ICP备2026067502号-1京公网安备11010502063487号