インスタンスメソッドのデコレータを作るとき、関数の代わりに __call__ を実装したクラスを使ってみると困ったことが起きる。
関数によるデコレータでは、メソッドが呼び出されたオブジェクトが関数に渡ってくる。
しかし、__call__ によるデコレータでは、__call__ メソッドにオブジェクトが渡ってこない。
class Decorator(object): def __init__(self, func): self.func = func def __call__(self): # メソッドを呼び出されたオブジェクトが届かないので、仕方なく self を渡してる return self.func(self) def decorate_a(func): return Decorator(func) def decorate_b(func): def wrap(called): return func(called) return wrap class FooMeta(type): def __new__(cls, cls_name, bases, attrs): for k, v in attrs.iteritems(): if not k.startswith('_'): print k, v return type.__new__(cls, cls_name, bases, attrs) class Foo(object): __metaclass__ = FooMeta @decorate_a def a(self): print 'do a', self @decorate_b def b(self): print 'do b', self Foo().a() Foo().b()
以下は実行結果
a <__main__.Decorator object at 0x109d26bd0> b <function wrap at 0x109d2c8c0> do a <__main__.Decorator object at 0x109d26bd0> do b <__main__.Foo object at 0x109d26c50>
関数によるデコレータの場合、つまり属性 b を metaclass で参照すると関数オブジェクトになる。
metaclass から Decorator オブジェクトを参照できるようにしようとの試みなのだけど、うまくいかない。