【Flask】初期化時の一つの謎を解明したので解説

flaskのチュートリアルのページを作成している時に、
ちょっと疑問が浮かんだ箇所があって、
解明できたので記録として残しておく。

Table of Contents(目次)

実行環境

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)

んん?

Flask app "study_flask"

んんんん???

お気付きであろうか。
直接実行したファイル内で__name__を名称としたFlask appを作成しているのに、
Flask app名が__main__ではなく、ファイル名になっていることに!

一応解説しておくと、
__name__という変数には基本的に拡張子なしのファイル名が保存される。
__name__が記述されたファイルが直接実行された時のみ"__main__"という文字列が入る。

今回の場合は直接実行しているので、
"__main__"という名称の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__”だったら、
最初に実行したファイルの名称を取ってくるという処理が書かれていた!!

なるほど。

まとめ

分かってみると結構単純だった。。

実はここにたどり着くまでに時間かなり使っちゃった。
わかってみると単純なんだけどわからないうちは複雑。

プログラミングなんて全部単純だよって言える人になりたいな。

Programing

Posted by iruka