コンテンツにスキップ

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

Python メタプログラミングのレジストリ図

メタプログラミングとは、コードでコード構造を整理または生成することです。日常の Python 工程で役立つのは、派手な技ではなく、自動登録、フィールド検証、定型処理の削減であることが多いです。

  • 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)

実行します。

Terminal window
python metaprogramming_demo.py

期待される出力:

Terminal window
json rows
['csv', 'json']
daily-import
error: name cannot be empty

レジストリは手書きの対応表を減らします。ディスクリプタはフィールド検証をフィールド定義の近くに置けます。

向いているもの:

  1. 多くのクラスを自動登録したい。
  2. フレームワークがプラグインを発見する必要がある。
  3. 多くのフィールドが同じ検証動作を共有する。
  4. 設定から繰り返し構造を作りたい。

普通のクラスや辞書のほうが分かりやすいなら、無理に使いません。

このページを終えたら、この証拠カードを残します。

Pythonパターン
デコレータ、イテレータ、ジェネレータ、並行処理プリミティブ、またはメタプログラミングフック
コード成果物
最小限の実行可能な例と表示された出力
使用場面
この pattern が AI app、pipeline、tool、または server を改善する場面
失敗確認
隠れた副作用、読みにくい抽象化、競合状態、または過度な設計
期待される成果
実践的なAIシステム用途のメモを含む小さな高度Python例
  • 高度に見せるためだけに動的な技を使う。
  • 振る舞いを深く隠しすぎて、デバッグしにくくする。
  • 小さな重複を消すために、全体の読みやすさを犠牲にする。

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" を試し、分かりやすい例外が出ることを確認します。目的は高度に見せることではなく、繰り返しの検証ルールをフィールド定義の近くに置くことです。