Python のコードオブジェクト(__code__)の詳細解析

関数の __code__ 属性はコードオブジェクトを保持しており、関数の内部構造に関する詳細情報を提供します。

コードオブジェクトの主要属性

def example(a, b, *args, c=10, **kwargs):
    x = a + b
    y = c * 2
    return x + y

code = example.__code__
co_name関数名
co_filename定義されたファイル名
co_firstlineno定義開始行番号
co_argcount位置引数の数(*args を除く)
co_kwonlyargcountキーワード専用引数の数
co_varnamesローカル変数名のタプル
co_freevars自由変数(クロージャで参照)
co_cellvarsセル変数(内部関数に渡す)
co_consts定数のタプル
co_codeバイトコード

具体的な値を確認

print(code.co_name)           # example
print(code.co_argcount)       # 2 (a, b)
print(code.co_kwonlyargcount) # 1 (c)
print(code.co_varnames)       # ('a', 'b', 'c', 'args', 'kwargs', 'x', 'y')
print(code.co_consts)         # (None, 10, 2)

クロージャと自由変数

def outer(x):
    def inner(y):
        return x + y
    return inner

closure = outer(10)
print(closure.__code__.co_freevars)  # ('x',)

co_freevars には、外側のスコープから参照している変数が記録されます。

コードオブジェクトの置き換え

コードオブジェクトを操作して関数の挙動を変えることも可能です(非推奨ですが理解として)。

def original():
    return 1

def replacement():
    return 2

original.__code__ = replacement.__code__
print(original())  # 2

実用的な活用

def get_function_info(func):
    code = func.__code__
    return {
        "name": code.co_name,
        "args": code.co_varnames[:code.co_argcount],
        "file": code.co_filename,
        "line": code.co_firstlineno,
    }

コードオブジェクトの理解は、デバッガーやプロファイラの開発、動的コード生成に役立ちます。