@classmethod を自作してみた
classmethodデコレータってどういう実装になってるんだろうっていう話が発端。ソースは見れないし、ググってもそれっぽいのは出てこなかったので自分でやってみた。Python 2.7で確認。
import文いれてもたった10行ですね。以下解説。
myclassmethodはディスクリプタになっていて、これを使うことでオブジェクトの参照動作をカスタマイズしてる。平たく言うとプロパティみたいなもので、myclassmethodクラスのインスタンスが参照 (get) された時に__get__が呼ばれるようになってる。デコレータはシンタックスシュガーなので普通の書き方に戻すとこうなる。
bar = myclassmethod(bar)
つまり、myclassmethodのインスタンスが生成されてそれがbar (クラス変数) に代入される。myclassmethod.__init__にはbarが渡されるが、この時点ではFooクラスはオブジェクト化されておらず、Fooクラスを参照する手立てがないのでとりあえず保存しておく。この時、barはただのfunctionである。
その後、Fooクラスがオブジェクト化されてbarが参照された時に、myclassmethod.__get__が呼ばれる。引数にはFooクラスのインスタンスとクラスオブジェクトが渡されるので、new.instancemethodを使ってself.funcをメソッド化してやる。クラスオブジェクトにboundすることでクラスメソッドができあがる。
new.instancemethodの第三引数がtypeなのは@classmethodデコレータで生成されたメソッドを見てそうしたんだけど、クラスオブジェクトのクラスがtypeだからなのかな。ここはちょっと自信ない。
以上。おしまい。
しかしこうもあっさりできるとは。あーあ、会社でうんうん唸ってたのはなんだったんだろーね、ほんと...。