翻译
Why do we pass__name__
to the Flask class?
当你学习 Flask 时,你被告知通过将 __name__
作为第一个参数传递给 Flask 类来创立 Flask 应用程序实例大多数开发人员这样做时不加思考,也不晓得它能达到什么成果。
在本文中,咱们将深入研究 Flask(__name__
)。最初,你不仅会齐全了解这个模式,而且还会晓得何时摈弃它并传递其余值。
__name__
是什么?
Python 将 __name__
变量设置为模块名称,因而该变量的值将依据应用它的 Python 源文件而有所不同。
例如,在应用程序顶级目录中名为 test.py 的模块中,__name__
的值为 test。如果 test.py 模块位于一个名为 my_package
的 Python 包中,那么 __name__
的值就是 my_package.test。
__name__
的值有两个非凡的例外:
- 在
__init__.py
包结构模块中,__name__
的值是包名而不是__init__.py
。例如,在 my_package/__init__.py 中,__name__
的值就是 my_package。 -
在应用程序的主模块(运行 Python 解释器的文件)中,
__name__
的值是非凡值__main__
。Flask 文档中的
__name__
如果你浏览 Flask 文档,
Flask
类的第一个参数称为 import_name。它被形容为“利用程序包的名称”。该文档倡议你“通常”通过为此参数传递__name__
来创立 Flask 实例,而无需具体阐明起因。
在题目为“对于第一个参数”的大节中,有更多对于 import_name 参数用处的信息,列出了它的三个不同用处:
- 查找文件零碎上的资源
- 被扩大应用以改良调试信息
- 更多(???)
很令人困惑,对吧?让咱们一个一个来看看。
寻找资源
乍一看,这实际上更容易了解。本上下文中的术语“资源”是指应用程序所需的附加文件,例如动态文件和模板文件。你有没有想过 Flask 如何晓得去哪里寻找这些文件?
它的工作形式如下。Flask 承受作为 import_name
传递的参数,它是导入包的名称,并尝试应用它通过查找具备该名称的模块对象来确定应用程序的根门路。一旦晓得了这个门路,它就会拼接动态和模板目录名称,这就是它获取这些文件的中央。
在 flask/helpers.py
模块中有一个名为 get_root_path()
的函数,Flask 应用它来获取应用程序的根目录。这个函数实现了导航 Python 导入零碎以定位名称为 import_name
参数的模块的所有脏活。
让咱们疾速浏览一下 get_root_path() 函数。对于上面的测试,我将应用 Flask Mega-Tutorial 中的 microblog 应用程序。正确装置此应用程序后,我将启动 Python 会话并应用几个不同的值调用 get_root_path() 函数以查看后果:
>>> from flask.helpers import get_root_path
# the app package
>>> get_root_path('app')
'/home/miguel/microblog/app'
# the flask package
>>> get_root_path('flask')
'/home/miguel/microblog/venv/lib/python3.8/site-packages/flask'
# the threading package
>>> get_root_path('threading')
'/home/miguel/.pyenv/versions/3.8.6/lib/python3.8'
# the config.py module
>>> get_root_path('config')
'/Users/mgrinberg/Documents/dev/python/microblog'
# the app/models.py module
>>> get_root_path('app.models')
'/Users/mgrinberg/Documents/dev/python/microblog/app'
# the app.api package
>>> get_root_path('app.api')
'/Users/mgrinberg/Documents/dev/python/microblog/app/api'
# the app.api.auth.py module
>>> get_root_path('app.api.auth')
'/Users/mgrinberg/Documents/dev/python/microblog/app/api'
从这些例子中,咱们能够推导出 Flask 用来确定根门路的规定:
- 如果调用
Flask()
将包的名称作为参数传递,那么应用程序的根门路就是包所在的目录。 - 如果调用
Flask()
将模块的名称作为参数传递,那么应用程序的根门路就是该模块所在的包的目录。
import_name
参数还有第二种用法。Flask 有一个不起眼的性能,称为 instance folders,这是一个非凡的文件夹,能够存储不受源代码管制的配置文件。确定应用程序实例文件夹地位的办法是一样的,应用 import_name
查找根门路,而后向其增加一个实例子目录。
我应该留神到,默认的根门路和实例门路都能够在 Flask 构造函数中用 root_path
和 instance_path
参数笼罩。
改良 Flask 扩大中的调试信息
这个很难弄清楚。我发现惟一一个应用 import_name
参数的 Flask 扩大是 Flask-SQLAlchemy。该扩大有一个 get_debug_queries() 函数,用于收集和记录在申请生命周期内收回的所有查问。记录的属性之一是收回查问在应用程序源代码中的地位。获取这些信息实际上十分艰难,Flask-SQLAlchemy 在查问实现时会沿着调用堆栈向上走,直到找到与应用程序的 import_name
匹配的源地位。
尽管这是一种十分酷的技术,但它也十分神奇和艰涩。我还没有看到它在任何其余 Flask 扩大中应用。
更多
我查看了 Flask 源代码以理解 import_name
参数的其余用法,并发现另外两个值得一提的案例。
一个是 Blueprint
类,它将蓝图名称作为第一个参数,将 import_name
作为第二个参数。参数在蓝图中的应用与查找蓝图特定资源无关,它的工作形式与应用程序实例中的雷同。
应用 import_name 参数的另一个乏味的中央是为应用程序实例命名。打印应用程序实例时会显示应用程序的名称:
>>> from flask import Flask
>>> app = Flask('foo')
>>> app
<Flask 'foo'>
此名称调配给 Click 命令行接口的 maingroup。如果将我的项目的 Flask CLI 作为一个 group 附加到 parent CLI 中,则此名称将是用于拜访 Flask 应用程序命令的 group 名称。