概要
- Pythonの__subclasshook__ を使った ABCの拡張的な利用法 の紹介
- パターンマッチング と subclasshook の 連携による型判定の柔軟性
- 動的なABC生成 と 複合判定 のテクニック
- __subclasshook__のキャッシュ挙動 と 副作用の実験
- 実践利用のリスク と ダークマジック的な側面
Pythonの__subclasshook__による型判定の拡張
- subclasshook は、 ABC(Abstract Base Class) が自分を サブクラスとみなす基準 を柔軟に定義可能
- 対象クラスがABCを 継承していなくても、 条件次第でサブクラス扱い できる
- 例:クラス名が回文ならTrueを返すPalindromicName ABC
Abba→ True、Baba→ Falseと判定
パターンマッチングとABCの連携
- Python 3.10以降のパターンマッチング は、
isinstance(obj, class)判定を内部で使用 - __subclasshook__を活用することで、パターンマッチの判定基準を乗っ取る ことが可能
- 例:NotIterable ABCを使い、
__iter__を持たないオブジェクトのみをマッチさせる
フィールド存在判定の応用
- パターンマッチングで「 特定のフィールドを持つ任意のオブジェクト」を判定可能
- 例:distanceプロパティを持つものをDistanceMetric ABCで判定
- Point2D, Point3Dなど、distance属性があればマッチ
パターンマッチングの柔軟性と制限
- オブジェクトの分解(デストラクチャリング) は、マッチ後に行われる
- ABC側で判定、オブジェクト側で分解 という分担が可能
- 例:z座標の有無や値による細かい分岐も記述可能
動的ABC生成による合成判定
- Not関数 で「特定クラスではないもの」を判定するABCを動的生成
- And関数 で「複数クラス条件を満たすもの」も判定可能
- 例:Iterableかつstrではないものだけをマッチさせる
__subclasshook__のキャッシュと副作用
- __subclasshook__の戻り値は型ごとにキャッシュされる
- 一度判定されると、以降は同じ結果が使われるため、 副作用を持たせても1回しか動作しない
- 例:最初の型だけTrueを返し、以降はFalseにするOneWay ABC
副作用を持つABCの例
- FlipFlop ABC :呼ばれるたびにTrue/Falseを交互に返す
- Ask ABC :型ごとにユーザーに許可を尋ねる
実用上の注意
- __subclasshook__によるパターンマッチの乗っ取りは「ダークマジック」
- 保守性や予測可能性を損なうため、通常の業務コードには非推奨
- 学術的・実験的な用途やライブラリの奥深い部分以外では使わない方が良い
おまけ:@propertyデコレータの役割
@propertyにより、distanceを メソッド呼び出しではなく属性アクセス として利用可能- __subclasshook__での属性チェックが簡単になる 利点
参考・謝辞
- Predrag Gruevski氏のフィードバック に感謝
- タイトルは「Crimes with Go Generics」から拝借
- 元記事の初稿は筆者の ニュースレター で公開済み
まとめ
- Pythonの ABCと__subclasshook__、 パターンマッチング を組み合わせることで、 柔軟かつ型安全性の低い判定ロジック が実現可能
- 本記事の内容は実務利用非推奨、好奇心・実験用として楽しむべき技法