だからタイトル長くない?
types.MethodType
使えば個々のインスタンスにメソッドを追加できるんだけど、types
をわざわざ import するのもなって感じにもなる。
で、
を読んでたら、関数オブジェクト(こいつは非データディスクリプタ)の__get__
内でtypes.MethodType
がよしなに呼び出されているのを見つけたので、これを使えばいいなと思いました。
class Klass(): def __init__(self): self.value = 10 def meth(self, value): self.value += value return self.value if __name__ == '__main__': c = Klass() c.meth = meth.__get__(c) print(c.value) # => 10 print(c.meth(5)) # => 15 print(c.__dict__) # => {'meth': <bound method meth of <__main__.Klass object at 0x000001994F40D9E8>>, 'value': 15}
ちょっと面白いのは、当たり前だけど、こうやって追加すると、クラスに定義されたメソッドではないから、インスタンスの属性辞書に直接メソッド(バウンドメソッド)が登録されるってことですね。まあ逆に言えば、いつもはインスタンスの属性辞書にメソッドは登録されておらず、あくまでクラスの属性を引っ張ってきてる(そのときにディスクリプタによってself
がバウンドされる)ってことですね。先にバウンドしておくか、呼び出し時にその都度バウンドしてもらうかってところが異なります。
ところで、メソッド(バウンドメソッドも)は新たに属性を加えられないっぽいですが、関数オブジェクトには色々属性を追加できます。
Klass.hoge.atr = 100 print(Klass.hoge.atr) print(c.hoge.atr) # => 100
クラスでメソッドを定義した場合、クラスからアクセスすればそれはただの関数オブジェクトなので、上の例みたいに新たに属性を追加できますが、インスタンスにバウンドメソッドをもたせた場合はそういうことができません(まあそんな使う性質でもないし、ほとんど差はないって思っていいとは思うけど)。