PlayGround Article Python, C Pythonを読む - 1 hiroki 2019年1月11日 Created with Sketch. 0 Created with Sketch. 475 Pythonのインタプリタ[CPython](https://github.com/python/cpython/tree/3.6)(3.6)の実装を`main`関数から読んでいきます. 第一回は`main`関数と関数`Py_Main`です. 誤りがございましたら,ご指摘いただけると幸いです. --- ## [`main`](https://github.com/python/cpython/blob/3.6/Programs/python.c#L19) C言語は必ず`main`関数から実行される.`CPython`の`main`関数は,`Programs/python.c`で定義されている. マクロ[`MS_WINDOWS`](https://github.com/python/cpython/blob/3.6/PC/python_ver_rc.h#L9)が定義されている場合,関数`wmain`を定義する.定義されていない場合,関数`main`を定義する.`wmain`はMicrosoft固有の仕様で,ワイド文字に対応し,`main`関数として振る舞う. 関数`wmain`および関数`main`は,コマンドライン引数を関数`Py_Main`に渡す. ``` wmain(int argc, wchar_t **argv) { return Py_Main(argc, argv); } ``` ## [`Py_Main`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L349) Pythonのインタプリタは次のインターフェイスを提供する. ### 対話モードで実行 `-i`オプションを指定して`Python`が実行された場合,または他のインターフェイスで実行されない場合,対話モードを実行する. 関数[`PyImport_ImportModule`](https://docs.python.jp/3/c-api/import.html#c.PyImport_ImportModule)に文字列`"readline"`を渡す. ``` v = PyImport_ImportModule("readline"); ``` 関数`PyImport_ImportModule`は,引数に与えられたモジュール名のモジュールをインポートする.上記の処理では文字列`"readline"`を引数に与えているので,モジュール[`readline`](https://docs.python.jp/3/library/readline.html#module-readline)をインポートする. 次に,関数[`RunStartupFile`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L131)と関数[`RunInteractiveHook`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L154)を実行する. ``` if (filename == NULL && stdin_is_interactive) { Py_InspectFlag = 0; /* do exit on SystemExit */ RunStartupFile(&cf); RunInteractiveHook(); } ``` 関数`RunStartupFile`は,対話モードで`Python`ソースコードを実行する前に,環境変数[`PYTHONSTARTUP`](https://docs.python.jp/3/using/cmdline.html#envvar-PYTHONSTARTUP)で指定されたファイルを読み込み, ``` char *startup = Py_GETENV("PYTHONSTARTUP"); ``` 関数[`PyRun_SimpleFileExFlags`](https://docs.python.jp/3/c-api/veryhigh.html#c.PyRun_SimpleFileExFlags)を実行し,ファイルの`Python`ソースコードを実行する. ``` (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf); ``` 関数`RunInteractiveHook`は,関数`PyImport_ImportModule`,関数[`PyObject_GetAttrString`](https://docs.python.jp/3/c-api/object.html#c.PyObject_GetAttrString),関数[`PyObject_CallObject`](https://docs.python.jp/3/c-api/object.html#c.PyObject_CallObject)を実行する.関数`PyImport_ImportModule`はモジュール[`sys`](https://docs.python.jp/3/library/sys.html#module-sys)をインポートし, ``` sys = PyImport_ImportModule("sys"); ``` 関数`PyObject_GetAttrString`はオブジェクト`sys`から属性[`__interactivehook__`](https://docs.python.jp/3/library/sys.html#sys.__interactivehook__)を取得し, ``` hook = PyObject_GetAttrString(sys, "__interactivehook__"); ``` 関数`PyObject_CallObject`は`__interactivehook__`を呼び出し, ``` result = PyObject_CallObject(hook, NULL); ``` 対話モードに対して環境変数`PYTHONSTARTUP`で指定されたファイルの`Python`ソースコードをフック(拡張)する. 最後に,関数`Py_Main`は関数[`run_file`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L312)を実行する. ``` sts = run_file(fp, filename, &cf); ``` 関数`run_file`は関数[`PyRun_AnyFileExFlags`](https://docs.python.jp/3/c-api/veryhigh.html#c.PyRun_AnyFileExFlags)を実行し, ``` run = PyRun_AnyFileExFlags(fp, filename_str, filename != NULL, p_cf); ``` 対話モードで`Python`ソースコードを実行する. ### コマンドを実行 `-c`オプションを指定して`Python`が実行された場合,`コマンド`として渡された`Python`ソースコードを実行する. 関数[`run_command`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L289)を実行する. ``` sts = run_command(command, &cf); ``` 関数`run_command`は関数[`PyRun_SimpleStringFlags`](https://docs.python.jp/3/c-api/veryhigh.html#c.PyRun_SimpleStringFlags)を実行し, ``` ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), cf); ``` 文字列`command`に含まれる`Python`ソースコードを実行する. ### モジュールを直接実行 `-m`オプションを指定して`Python`が実行された場合,`モジュール`をスクリプトとして実行する. 関数[`RunModule`](https://github.com/python/cpython/blob/3.6/Modules/main.c#L181)を実行する. ``` sts = (RunModule(module, 1) != 0); ``` 関数`RunModule`は関数`PyImport_ImportModule`を実行し,モジュール[`runpy`](https://docs.python.org/ja/3/library/runpy.html#module-runpy)をインポートする. ``` runpy = PyImport_ImportModule("runpy"); ``` 最後に,関数`Py_Main`は関数`run_file`を実行する. ``` sts = run_file(fp, filename, &cf); ``` 関数`run_file`は関数`PyRun_AnyFileExFlags`を実行し, ``` run = PyRun_AnyFileExFlags(fp, filename_str, filename != NULL, p_cf); ``` モジュールの`Python`ソースコードを直接実行する. ### ファイルを実行 コマンドライン引数にファイル名が与えられた場合,ファイルをスクリプトとして実行する. 関数`_Py_wfopen`を実行してファイルを読み込み, ``` fp = _Py_wfopen(filename, L"r"); ``` 関数`Py_Main`は関数`run_file`を実行する. ``` sts = run_file(fp, filename, &cf); ``` 関数`run_file`は関数`PyRun_AnyFileExFlags`を実行し, ``` run = PyRun_AnyFileExFlags(fp, filename_str, filename != NULL, p_cf); ``` ファイルの`Python`ソースコードを実行する. --- エタらなければ,続きます.