1. ホーム
  2. python

[解決済み] Pythonのコードの行は、そのインデント・ネストレベルを知ることができますか?

2022-04-28 21:56:48

質問

このようなものから

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

このようなものが欲しいのですが。

1
2
3

このように、コードは自分自身を読み取ることができるのでしょうか?

私が欲しいのは、コードのよりネストされた部分からの出力だけです。これによってコードが読みやすくなるのと同じように、出力も読みやすくなるはずです。

もちろん、これを手動で実装することも可能で、例えば .format() しかし、私が考えていたのは、カスタムプリント機能で print(i*' ' + string) ここで i はインデントレベルです。これは、私のターミナルで読みやすい出力を作る手っ取り早い方法でしょう。

手間のかかる手作業での書式設定を避ける、もっと良い方法はないでしょうか?

どのように解決するのですか?

スペースやタブではなく、ネストレベルでインデントを行いたい場合は、事態が厄介になります。たとえば、次のようなコードです。

if True:
    print(
get_nesting_level())

への呼び出しは get_nesting_level の行に先頭の空白がないにもかかわらず、実際には一階層分ネストしています。 get_nesting_level を呼び出します。一方、次のようなコードでは

print(1,
      2,
      get_nesting_level())

への呼び出しは get_nesting_level は、その行の先頭に空白があるにもかかわらず、0レベルの深さにネストされています。

次のようなコードで

if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())

への2つの呼び出しは get_nesting_level は、先頭の空白が同じであるにもかかわらず、異なるネストレベルにあります。

次のようなコードで

if True: print(get_nesting_level())

は、ネストされた0レベルなのか、1レベルなのか?という点では INDENTDEDENT トークンを正式な文法に当てはめると、0レベルの深さですが、同じように感じないかもしれませんね。


これをやるなら、ファイル全体を呼び出しのところまでトークン化して、カウント INDENTDEDENT トークンを使用します。は tokenize モジュールは、このような機能には非常に便利です。

import inspect
import tokenize

def get_nesting_level():
    caller_frame = inspect.currentframe().f_back
    filename, caller_lineno, _, _, _ = inspect.getframeinfo(caller_frame)
    with open(filename) as f:
        indentation_level = 0
        for token_record in tokenize.generate_tokens(f.readline):
            token_type, _, (token_lineno, _), _, _ = token_record
            if token_lineno > caller_lineno:
                break
            elif token_type == tokenize.INDENT:
                indentation_level += 1
            elif token_type == tokenize.DEDENT:
                indentation_level -= 1
        return indentation_level