別のクラスのメソッド セットを模倣し、プロキシ経由で後者のように動作するクラスを生成する必要があります。たとえば、IfBase
は模倣するDeleguate
クラスであり、次のように動作する必要があるクラスBase
です。
b = Base(args)
b.any_function()
と厳密に同等です
d = Deleguate(b)
d.any_function()
Deleguate
に既に存在する関数を使用する場合Base
、上書きされません。これは、継承とメソッドのオーバーライドで期待される種類の動作です。継承は、私が取り組んでいるプロジェクトのコンテキストではオプションではありません (他の制約の中でも特に、ファクトリ コードにアクセスできません)。そして、それが物事を複雑にしています。
したがって、「プロキシ」デコレータをコーディングすることにしました。
import inspect
def proxy(bridge, target):
def proxyfy(cls):
for _, func in inspect.getmembers(target, predicate=inspect.ismethod):
fname = func.__name__
if fname in cls.__dict__:
print 'ignoring %s.%s' % (cls, fname)
continue
print 'adding %s.%s' % (cls, fname)
def proxy_func(self, *args, **kwargs):
print 'calling %s.%s.%s' % (cls, bridge, fname)
bridge_member = getattr(self, bridge)
return getattr(bridge_member, fname)(*args, **kwargs)
setattr(cls, fname, proxy_func)
return cls
return proxyfy
class Base(object):
def __init__(self, i):
self._i = i
def __bar(self):
print 0
def foo(self):
print self._i
def foo2(self):
print 2 * self._i
@proxy('_proxy', Base)
class Deleguate(object):
def __init__(self, base):
self._proxy = base
def foo2(self):
print 4 * self._proxy._i
d = Deleguate(Base(1))
d.__bar() # d._proxy.__bar()
d.foo() # d._proxy.foo()
d.foo2() # d.foo2()
次の出力が得られます。
adding <class '__main__.Deleguate'>.__bar
ignoring <class '__main__.Deleguate'>.__init__
adding <class '__main__.Deleguate'>.foo
ignoring <class '__main__.Deleguate'>.foo2
calling <class '__main__.Deleguate'>._proxy.foo2
2
calling <class '__main__.Deleguate'>._proxy.foo2
2
4
新しいクロージャーを割り当てると思ったのですsetattr(cls, fname, proxy_func)
が、引数は各ループステップで上書きされ、最後の関数の引数のみfoo2
が保持されます。Deleguate
したがって、引数を使用する「生成された」関数を呼び出すfoo2
...
クロージャー引数が上書きされるのはなぜですか? そのようなプロキシ コードを生成する方法はありますか? 予想される出力は次のとおりです。
adding <class '__main__.Deleguate'>.__bar
ignoring <class '__main__.Deleguate'>.__init__
adding <class '__main__.Deleguate'>.foo
ignoring <class '__main__.Deleguate'>.foo2
calling <class '__main__.Deleguate'>._proxy.__bar
0
calling <class '__main__.Deleguate'>._proxy.foo
1
4