すべてのクラスには__bases__という隠しフィールドがあるので、そこに任意のスーパークラスを作って追加する
■何がしたいか
たとえば以下のようなクラスがあります。
class Foo: def do_something(self, x): print x return
このクラスのソースコードに指一本触れずに以下のメソッドを追加したい。
def another_method(self, x, y): print x+y return
って将軍様が言っていたので、一⑨さんは考えました。
■チーン!ひらめいた!
まずは以下のようにスーパークラスになるクラスを作ります。
class SampleCategory: def another_method(self, x, y): print x+y return
そしてここからがポイント。__bases__というTupleに、今作ったスーパークラスのtype型を追加します。
スーパークラスを宣言した後で・・・
from com.akisute.example import Foo Foo.__bases__ += (SampleCategory,)
これだけです。
なぜかこれでうまくいくのがPythonのふしぎ。
実際のソースコードの例は以下のようになります(以下、拙作のプログラムから抜粋)
#!/usr/bin/env python # encoding: utf-8 """Login Authentication plugin. Extends BasicController to give it an additional function for authentication using Google account. """ import sys import os class LoginAuthPlugin: def is_login(self): """Returns True if requesting user is logged in.""" #Do some work here return false from gaeo.controller import BaseController BaseController.__bases__ += (LoginAuthPlugin,)
JavaScriptのprototype書き換えにも似ていますね。
ただしprototype書き換えに比べて優れているのは、__bases__はTupleなので、簡単に好きなだけスーパークラスを追加することが出来ます。
(prototypeだと複数のスーパークラスを追加するのがきわめて困難)
from com.akisute.example import Foo Foo.__bases__ += (SampleCategory,) Foo.__bases__ += (AnotherCategory,)
■元ネタ
GAEOでpluginを読み込んでBaseControllerを拡張するときにこのテクが使われていました。
GAEO作った人は凄い。