@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だからなのかな。ここはちょっと自信ない。

以上。おしまい。

しかしこうもあっさりできるとは。あーあ、会社でうんうん唸ってたのはなんだったんだろーね、ほんと...。