🐕

Pythonのインデント = ブロックを決めている実装を追う

に公開

はじめに

Pythonのコードブロックはインデント4つなどで決めていますが、実装はどうなっているのでしょうか?気になったので調べてみました。

準備

cpythonは下記のgithubリポジトリで公開されています。
今回は、ローカルでファイルを確認したいためクローンします。
https://github.com/python/cpython

cpythonをクローン

git clone https://github.com/python/cpython.git
cd cpython

調査

対象ファイル

確認

tok_get_normal_mode - Parser/lexer/lexer.c:501

  1. インデントレベルの変化検出とINDENT/DEDENTトークン生成の中核処理
  • lexer.c:514-607: インデントレベル計算・比較ロジック
    • 515行: if (tok->atbol) で行頭チェック
    • 516-546行: スペース・タブ文字をカウントしてインデントレベルを計算
    • 571-606行: 現在のインデントと前回のインデントを比較し、INDENT/DEDENT生成を決定
  • lexer.c:613-631: INDENT/DEDENTトークン生成
    • 614行: if (tok->pendin != 0) でペンディングトークンをチェック
    • 615-621行: tok->pendin < 0の場合DEDENTトークン生成(621行)
    • 623-630行: tok->pendin > 0の場合INDENTトークン生成(629行)
  1. インデントレベルの一貫性を検証
  • 571-575行: 現在レベルと一致する場合のaltindstackチェック
  • 584-585行: INDENT時のaltcolチェック
  • 598-601行: DEDENT時の不整合チェック(E_DEDENT設定)
  • 603-605行: DEDENT時のaltindstackチェック
  1. インデント状態管理
  • int indent (87行): 現在のインデントレベルインデックス
  • int indstack[MAXINDENT] (88行): インデントレベルスタック
  • int atbol (89行): 行頭フラグ
  • int pendin (90行): ペンディングINDENT/DEDENT数

フロー図

まとめ

PEP8でインデントは空白4つなど、準拠すべきルールが定められていますがインデントは4で固定でないことやそのアルゴリズムがわかりました。皆さんの学習の補助に使っていただけると幸いです。

Discussion