__call__ と callable がよくわかんなかった話

なんかライブラリとかみてるとたまに __call__ とか callable がでてきた

なので軽く調べたけど、a = A(); a() でフックっぽく呼ばれるというのはわかったけどなにがどう便利なのか正直わかんなかった。

イマイチ __call__ がどう便利なのかがわからなかった。寝よう
ああ、callableについて調べるの忘れてた。明日でいいや

そしたら早速 @xxxxxxx さんが返信をくれた。ためしてみる

状態を持った関数っぽいふるまいをするオブジェクトを作れる

__call__ method
あとそれとは別に似たような名前で callable ってのを目にする機会があったけど正直よくわかんなくておまじないだったのでついでにしらべた
callable のドキュメントは以下
2. Built-in Functions — Python v2.7.5 documentation

callable(object)
Return True if the object argument appears callable, False if not. If this returns true, it is still possible that a call fails, but if it is false, calling object will never succeed. Note that classes are callable (calling a class returns a new instance); class instances are callable if they have a __call__() method.

argument が object なら True でそうじゃなきゃ False らしい

class A(object):
    def __init__(self):
        print 'init'
        self.value = 0

    def __call__(self, *arg, **kwarg):
        print 'called'
        print arg, kwarg
        self.value += 1
        print self.value

    x = 1
    y = 'y'
    z = {'aaa': 'bbb'}

a = A()
# init
a(1,2, hoge='moge')
#called
#(1, 2) {'hoge': 'moge'} argument がはいっている
#1 インクリメントされている
a()
#called
#() {}
#2 インクリメントされている
a()
#called インクリメントされている
#() {}
#3
print callable(a)
# True object なので True
print callable(a.x)
# False int なので False
print callable(a.y)
# False str なので False
print callable(a.z)
# False dict なので False

なるほどね
ちなみにライブラリを眺めてると __call__(self, *args, **kwargs) って記述がわりとある。うーーーん、正直どう便利なのかまだわからないが、すこしだけ挙動を把握した

追記

@xxxxxxxxxx

関数(callable)しか指定できないところで状態を保持できる。何回呼び出されたかを記録したりとか、2回目の呼び出しでは内部に保持したキャッシュを返すとか。

なるほど!ほへーーーーー。あとは実装をみて理解を深めるしかないっすね