Pythonで特異メソッド

メソッドは普通class文の中で定義して、そのクラスのインスタンスはみんな同じメソッドを共有するものですが、特定のインスタンスだけための特注品のメソッドを、特異メソッドと言います。

Rubyには特異メソッドのための構文がありますが、Pythonにはありません。

しかし、Pythonでは特異メソッドは不可能・・・というわけではありません。

それにはnew.instancemethodを使います。

import new

class A(object):
    def __init__(self, n):
        self.n = n

def spam(self, x):
    return self.n*x + 2

a1 = A(3)
a1.spam = new.instancemethod(spam, a1, A) 
print a1.spam    # => <bound method A.spam of <__main__.A object at 0x00B014D0>>
print a1.spam(3) # => 11
a2 = A(3)
print a2.spam(3) # AttributeErrorが発生


a1にspamメソッドがバッチリ追加されています。a2はもとのままです。ちなみにRubyのようにstrやintにまで特異メソッドを追加する事は出来ないので悪しからず。


ところで、一々
foo.bar = new.instancemethod(bar, foo, Klass)と書くのは面倒なので、デコレータにしてしましょう。

import new

def singletonmethod(obj):
    def f(function):
        m = new.instancemethod(function, obj, type(obj)) 
        setattr(obj, function.__name__, m)
        return function
    return f

class A(object):pass

a1 = A(3)
@singletonmethod(a)
def spam(self, x):
    return 3*x + 2

print a1.spam    # => <bound method A.spam of <__main__.A object at 0x00B014D0>>
print a1.spam(3) # => 11
a2 = A(3)
print a2.spam(3) # AttributeErrorが発生

これで書きやすくなった・・・かな?
しかし「Pythonで特異メソッドはこう書く!」といった記事はそれなりに見かけますが、

Pythonで特異メソッドを使えばこんなにハッピーですよ!」という記事は見たことがありません(僕は)。

新しいメソッドが必要なら、クラスを継承して新しいクラスを作ればいいだけなので、特異メソッドはさほど重要ではないのかもしれません。

参考