【Flask】初期化時の一つの謎を解明したので解説【無駄知識】
Flaskを使ってアプリケーションを作成している時に、ちょっとした疑問が浮かんだ箇所がありまして、その疑問を調査によって解消することができたので備忘録として残しておきます。
実行環境
OS: Ubuntu 18.04.2 LTS
python: 3.6.8
Flask: 1.1.1
疑問の内容
以下のFlaskアプリケーションを起動させるファイルを実行してみた時に事件は起こりました。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World!"
app.run()
上記コードが記載されたファイルを実行してみた結果は以下になります。
$ python study_flask.py
* Serving Flask app "study_flask" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
ちゃんとFlaskのサーバーが起動してくれています。
しかし以下の一行が引っかかりました。
* Serving Flask app "study_flask" (lazy loading)
直接実行したファイル内で__name__
を名称としたFlaskを作成しているのに、
Flask app名が__main__
ではなく、ファイル名になっています。
__name__
とはpythonの予約語の変数で、基本的に拡張子なしのファイル名が保存されています。
ただし__name__
が記述されたファイルが直接実行された時のみ__main__
という文字列が代入されます。
今回の場合は__name__
が記載されたファイルを直接実行しているので、
__name__
という名称のFlask appが出来上がると思っていたのですが、実際にはファイルの名称が格納されていました。
調査結果
検索して調査してみたのですが、解説が載っているサイトを見つけられなかったため、直接Flaskのソースコードを読むことにしました。
class Flask(_PackageBoundObject):
"""The flask object implements a WSGI application and acts as the central
object. It is passed the name of the module or package of the
application. Once it is created it will act as a central registry for
the view functions, the URL rules, template configuration and much more.
The name of the package is used to resolve resources from inside the
package or the folder the module is contained in depending on if the
package parameter resolves to an actual python package (a folder with
an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
~~省略〜〜
"""
def __init__(
self,
import_name,
static_url_path=None,
static_folder="static",
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder="templates",
instance_path=None,
instance_relative_config=False,
root_path=None,
):
__name__
は直接flaskの名称になるのではなく、import_nameの引数として渡されている様です。またこのimport_nameはself.import_nameに代入されていました。
さらに読み進めていくと以下のような関数を発見。
def name(self):
"""The name of the application. This is usually the import name
with the difference that it's guessed from the run file if the
import name is main. This name is used as a display name when
Flask needs the name of the application. It can be set and overridden
to change the value.
.. versionadded:: 0.8
"""
if self.import_name == "__main__":
fn = getattr(sys.modules["__main__"], "__file__", None)
if fn is None:
return "__main__"
return os.path.splitext(os.path.basename(fn))[0]
return self.import_name
色々処理していますが、重要なのはここ↓です。
if self.import_name == "__main__":
fn = getattr(sys.modules["__main__"], "__file__", None)
"~~省略~~"
return os.path.splitext(os.path.basename(fn))[0]
もしself.import_nameが__main__
だったら、最初に実行したファイルの名称を取ってくるという処理が書かれていました。
まとめ
実際にコードを一から追ってみると結構単純でしたが、この答えにたどり着くまでに時間かなり使ってしまいました。
細かなところが気になってしまう性格は損しますね。でも直す気はないです。
Discussion