E.B.4 メタプログラミング

メタプログラミングとは、コードでコード構造を整理または生成することです。日常の Python 工程で役立つのは、派手な技ではなく、自動登録、フィールド検証、定型処理の削減であることが多いです。
準備するもの
Section titled “準備するもの”- Python 3.10+
- 外部パッケージ不要
- クラスの基本理解
- Registry(レジストリ):利用可能な実装を覚えておくマッピング。
- デコレータ登録:デコレータでクラスや関数をレジストリに追加すること。
- Descriptor(ディスクリプタ):属性の読み書きを制御するオブジェクト。
__set_name__:ディスクリプタが自分に割り当てられた属性名を知るためのメソッド。- 動的クラス:実行時に作られるクラス。代表例は
type。
レジストリとディスクリプタを動かす
Section titled “レジストリとディスクリプタを動かす”metaprogramming_demo.py を作成します。
REGISTRY = {}
def register(name): def decorator(cls): REGISTRY[name] = cls return cls
return decorator
@register("csv")class CsvLoader: def load(self): return "csv rows"
@register("json")class JsonLoader: def load(self): return "json rows"
class NonEmpty: def __set_name__(self, owner, name): self.private_name = "_" + name
def __get__(self, instance, owner): if instance is None: return self return getattr(instance, self.private_name, None)
def __set__(self, instance, value): if not value: raise ValueError("name cannot be empty") setattr(instance, self.private_name, value)
class JobConfig: name = NonEmpty()
loader = REGISTRY["json"]()print(loader.load())print(sorted(REGISTRY))
config = JobConfig()config.name = "daily-import"print(config.name)
try: config.name = ""except ValueError as error: print("error:", error)実行します。
python metaprogramming_demo.py期待される出力:
json rows['csv', 'json']daily-importerror: name cannot be emptyレジストリは手書きの対応表を減らします。ディスクリプタはフィールド検証をフィールド定義の近くに置けます。
使う価値がある場面
Section titled “使う価値がある場面”向いているもの:
- 多くのクラスを自動登録したい。
- フレームワークがプラグインを発見する必要がある。
- 多くのフィールドが同じ検証動作を共有する。
- 設定から繰り返し構造を作りたい。
普通のクラスや辞書のほうが分かりやすいなら、無理に使いません。
このページを終えたら、この証拠カードを残します。
- Pythonパターン
- デコレータ、イテレータ、ジェネレータ、並行処理プリミティブ、またはメタプログラミングフック
- コード成果物
- 最小限の実行可能な例と表示された出力
- 使用場面
- この pattern が AI app、pipeline、tool、または server を改善する場面
- 失敗確認
- 隠れた副作用、読みにくい抽象化、競合状態、または過度な設計
- 期待される成果
- 実践的なAIシステム用途のメモを含む小さな高度Python例
よくある間違い
Section titled “よくある間違い”- 高度に見せるためだけに動的な技を使う。
- 振る舞いを深く隠しすぎて、デバッグしにくくする。
- 小さな重複を消すために、全体の読みやすさを犠牲にする。
yaml loader を追加し、sorted(REGISTRY) に含まれることを確認してください。次に retry_count フィールド用の IntegerRange(min_value, max_value) ディスクリプタを作ります。
参考実装と解説
yaml loader は既存 loader と同じ仕組みで登録します。別の対応表を手で編集しなくても、sorted(REGISTRY) に yaml が含まれる状態にします。
IntegerRange ディスクリプタは、整数以外と範囲外の値を拒否する必要があります。実用的な確認として、retry_count = 3 を設定してから、retry_count = -1 や "3" を試し、分かりやすい例外が出ることを確認します。目的は高度に見せることではなく、繰り返しの検証ルールをフィールド定義の近くに置くことです。