Pythonソースコードを解析して、メソッドブロックや関数ブロックの定義行と最終行を取得することがありました。
Pythonでは標準モジュールのast
を使ってソースコードを解析できるため、試した時のメモです。
32.2. ast — 抽象構文木 — Python 3.6.1 ドキュメント
なお、以下のページが大変参考になりました。ありがとうございました。
Python: ast (Abstract Syntax Tree: 抽象構文木) モジュールについて - CUBE SUGAR CONTAINER
環境
方法
上記の参考ブログ同様、astモジュールと再帰を組み合わせて解析します。
- メソッドや関数の定義は、
ast.FunctionDef
クラス - メソッド名や関数名は、
ast.FunctionDef.name
で取得 - 行数は
ast.FunctionDef.lineno
などのlineno
属性で取得- クラスによっては、
lineno
属性がないことに注意
- クラスによっては、
collect_method_last_line_no.py
import ast class Collection: def __init__(self, name='', def_line_no=0, last_line_no=0): self.name = name self.def_line_no = def_line_no self.last_line_no = last_line_no class MethodLastLineNoCollector: def __init__(self): self.result = {} self.searched_line_no = 0 def run(self, node): if isinstance(node, ast.FunctionDef): self.result[node.lineno] = Collection(node.name, def_line_no=node.lineno) for child in ast.iter_child_nodes(node): self.run(child) if hasattr(node, 'lineno'): # 探索した最終行を取得 # 再帰で探すので、node.linenoは 1 > 2 > 3 > 2 > 1 となる if node.lineno > self.searched_line_no: self.searched_line_no = node.lineno # 再帰で探した時の帰りに、最終行を設定する else: if self.result.get(node.lineno): self.result[node.lineno].last_line_no = self.searched_line_no if __name__ == '__main__': FILENAME = 'target.py' with open(FILENAME, 'r') as f: source = f.read() tree = ast.parse(source, FILENAME) collector = MethodLastLineNoCollector() collector.run(tree) for v in collector.result.values(): print(f'{v.name} -> def:{v.def_line_no}, last:{v.last_line_no}')
動作確認をします。例えば、
target.py
def foo_function(): pass def innner_foo_function(): pass class Bar: def bar_method(self): pass def bar_inner_method(self): pass def bar_other_method(self): pass class InnerBar: def innter_bar_method(self): pass if __name__ == "__main__": pass
というソースコードがあったとします。
collect_method_last_line_no.py
を実行します。
$ python collect_method_last_line_no.py foo_function -> def:1, last:5 innner_foo_function -> def:4, last:5 bar_method -> def:9, last:13 bar_inner_method -> def:12, last:13 bar_other_method -> def:15, last:16 innter_bar_method -> def:19, last:20
動作しているようです。
ソースコード
GitHubに上げました。collect_method_last_line_no
ディレクトリの中が今回のものです。
thinkAmi-sandbox/python_ast-sample