Python inspectとは?オブジェクトの中身を調べる方法を解説

inspectは、実行中のオブジェクトの中身を調べる標準モジュールです。

関数の引数・ソースコード・クラスの構造などをプログラムから取得できます。


何ができるのか

import inspect

def greet(name, greeting="こんにちは"):
    """挨拶を返す。"""
    return f"{greeting}、{name}さん"

print(inspect.signature(greet))
print(inspect.getdoc(greet))
print(inspect.isfunction(greet))

実行結果:

(name, greeting='こんにちは')
挨拶を返す。
True

引数の定義・説明文・種類——どれもコードを読まずに取得できています。


主な関数

関数 取得できるもの
signature() 引数の定義
getdoc() docstring(整形済み)
getsource() ソースコード
getmembers() 属性の一覧
getfile() 定義されたファイル
stack() 呼び出し履歴

さらにis○○()という判定関数が多数あります。

import inspect
import asyncio

async def af(): pass

print("isfunction:", inspect.isfunction(greet))
print("isclass:", inspect.isclass(int))
print("iscoroutinefunction:", inspect.iscoroutinefunction(af))
print("ismethod:", inspect.ismethod(greet))

実行結果:

isfunction: True
isclass: True
iscoroutinefunction: True
ismethod: False

ismethod()がFalseなのは、greetがクラスに属さない普通の関数だからです。メソッドとの区別に使えます。


使いどころ

  • デコレータ——引数の定義を保ったまま関数を包む
  • プラグイン機構——モジュール内のクラスを自動で集める
  • 自動ドキュメント生成——docstringと引数を抽出する
  • フレームワーク——引数名を見て値を自動で渡す
  • デバッグ——どこから呼ばれたか調べる

4つ目はpytestのfixtureやFastAPIの依存性注入で使われている仕組みです。引数名から必要なものを判断して渡しています。


クラスの中身を調べる

import inspect

class Calc:
    """計算用のクラス"""
    version = "1.0"

    def add(self, a, b):
        return a + b

    def sub(self, a, b):
        return a - b

for name, obj in inspect.getmembers(Calc, inspect.isfunction):
    print(name, inspect.signature(obj))

実行結果:

add (self, a, b)
sub (self, a, b)

第2引数で絞り込めます。これを書かないと__class__などの特殊属性まで大量に出てきます。

詳しくは「Python inspect.getmembers()とは?オブジェクトの中身を一覧する方法」で解説しています。


ソースコードを取得する

import inspect

print(inspect.getsource(greet))

実行結果:

def greet(name, greeting="こんにちは"):
    """挨拶を返す。"""
    return f"{greeting}、{name}さん"

定義そのものが文字列で返ります。

ただしファイルが必要です。対話シェルで定義した関数や、組み込み関数には使えません。

inspect.getsource(len)

実行結果:

TypeError: module, class, method, function, traceback, frame, or code object was expected, got builtin_function_or_method

「Python inspect.getsource()とは?ソースコードを取得する方法」を参照してください。


dir()との違い

print(dir(Calc)[:3])
print(inspect.getmembers(Calc)[:1])

実行結果:

['__class__', '__delattr__', '__dict__']
[('__class__', <class 'type'>)]

dir()は名前のリストを返すだけですが、getmembers()は名前と実体のペアを返します。

dir() inspect.getmembers()
戻り値 名前だけ (名前, 実体)
絞り込み できない できる
手軽さ 高い やや冗長

対話的に確認するならdir()、プログラムで処理するならgetmembers()です。


使いすぎない

inspectは強力ですが、注意点があります。

  • 処理が重い——ループの中で呼ぶものではない
  • 実装に依存する——引数名を変えただけで壊れる
  • 読み手に何が起きているか分かりにくい

「引数名を見て自動で処理を分岐する」ようなコードは、動きが追いにくく保守しづらくなります。

設定や引数で明示できるなら、そちらを選んでください。フレームワークを作る側の道具だと考えると、使いどころを誤りません。


inspectのまとめ

  • 実行中のオブジェクトの中身をプログラムから調べる
  • signature()で引数、getdoc()で説明文
  • getsource()はファイルがないと使えない
  • getmembers()は第2引数で絞り込む
  • dir()は名前だけ、getmembers()は実体つき
  • 処理は重く、実装に依存する——多用しない

あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら