Pythonクイズの回答(特異メソッド)

Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import new
>>> class A(object):pass
...
>>> def test(self):
...   print "test"
...
>>> a = A()
>>> a.test = new.instancemethod(test, a, a.__class__)
>>> a.test
<bound method A.test of <__main__.A object at 0x00D60F90>>
>>> a.test()
test
>>> b = A()
>>> b.test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'test'

new.pyの中でimportしているtypes.pyのソースを見ると以下のようなことをやっている。

>>> class _C:
...   def _m(self): pass
... 
>>> _x = _C()
>>> a.test = type(_x._m)(test, a, a.__class__)
>>> a.test()
test
>>> type(_x._m)
<type 'instancemethod'>

ここでinstancemethod型をtype(_x._m)で取得し、instancemethod型のコンストラクタを呼び出している。シグネチャは、help(_x._m)で表示されるが

instancemethod(function, instance, class)

で、インスタンスメソッドオブジェクトが作成される。それをインスタンスaのtest属性にバインドする。クラスAの属性は変更していないので、インスタンスbからはサーチされない。もちろんクラスAにバインドするならunbound methodを用いる必要がある。


追記(2008/10/19):

newモジュールは3.0でなくなってしまうのでtypesを使う方を回答としています。

知らなかった。

実際これらtypeからインスタンス生成を生成するコードはCで書かれています。

Cで実装されているのであればいくらでも機能を追加できる。typeもdirと同じで魔法の関数だなあ。