(クラスインスタンスにメソッドを動的に追加する方法について。クラスに対してメソッドを動的に追加するのは簡単かつ自明だけど、インスタンスに追加するのはひとひねり必要です。)
Pythonのクラスインスタンスには自由にアトリビュートを追加できる。データアトリビュートなら、こんな感じ。
>>> class C:
... pass
...
>>> c = C()
>>> c.name = 'I am a C.'
>>> c.name
'I am a C.'
関数も追加できる。
>>> def f():
... print 'f() is calld.'
...
>>> c.f = f
>>> c.f()
f() is calld.
関係ないけど、関数はラムダ式でもいい。
>>> c.g = lambda x: x*x
>>> c.g(10)
100
ここで追加した関数は、ただの関数なので、メソッドにはなっていない。つまり、第1引数として self を渡してもらえない。
>>> def m(self):
... print 'I am a %s.'%(self)
...
>>> c.m = m
>>> c.m()
Traceback (most recent call last):
File "", line 1, in ?
TypeError: m() takes exactly 1 argument (0 given)
メソッドにするには、 new.instancemethod を使えばよい。
>>> import new
>>> c.m = new.instancemethod(m, c, type(c))
>>> c.m()
I am a <__main__.C instance at 0x00DFD328>.
これはたぶんRubyの特異メソッドみたいなもので、ここで指定したインスタンスのみに適用される。クラスの定義は変わらないので、別のインスタンスでは、追加したメソッドは使えない。
>>> d=C()
>>> d.m()
Traceback (most recent call last):
File "", line 1, in ?
AttributeError: C instance has no attribute 'm'
ちなみに、クラスに対してあとからメソッドを追加するのは、とてもシンプル。クラスのアトリビュートに追加するだけで、ちゃんとself を渡してくれる。
>>> C.mm = m
>>> d.mm()
I am a <__main__.C instance at 0x00D8FC88>.
こういう、宣言的ではない記法って、プログラマにはわかりやすいと思うんですが、どうなんでしょう。
追記
組み込みクラス(strとかint)には、あとからメソッドを追加することはできないみたいです(クラスにもインスタンスにも)。ちょっと残念だけど、まああまりやるべきことではない気もする。