1

次のようなxmlrpcサーバーを実行しています

from SimpleXMLRPCServer import SimpleXMLRPCServer

def add(x,y):
    return x+y

server = SimpleXMLRPCServer(("localhost", 8000))
server.register_function(add, 'add.numbers')
server.serve_forever()

これは、次のコード内で使用されます。

import xmlrpclib

class DeviceProxy(object):
    def __init__(self, uri):
        self.rpc = xmlrpclib.ServerProxy(uri)
    def __getattr__(self, attr):
        return getattr(self.rpc, attr)

original = DeviceProxy.__getattr__

def mygetattr(device, attr):
    def wrapper(*args, **kw):
        print('called with %r and %r' % (args, kw))
        return original(device, attr)(*args, **kw)
    return wrapper

DeviceProxy.__getattr__ = mygetattr

dev = DeviceProxy("http://localhost:8000/RPC2")
print dev.add.numbers(4,6)

ご覧のとおり、クラスはこの質問の範囲外の理由でプロキシをProxyラップし、メソッドを介して任意の呼び出しを転送します。この質問の範囲外のさらなる理由については、このメソッドを別のメソッドでラップ/置換して、たとえば、呼び出された関数の名前、引数などを出力する必要があります (関連する質問hereを参照)。xmlrpc__getattr____getattr__

しかし、このアプローチは機能せず、次のエラーが発生します。

AttributeError: 'function' object has no attribute 'numbers'

この例は、私が

  • DeviceProxy.__getattr__他のものに置き換えないでください
  • DeviceProxy.__getattr__関数に置き換えます

    defダミー(インスタンス、属性):オリジナル(デバイス、属性)を返す

  • xmlrpc関数の名前をゼロドットの名前に置き換えます (例: のsum代わりにsum.numbers)

次の xmlrpc プロキシ経由の直接呼び出しが期待どおりに機能することを確認できます。

dev = xmlrpclib.ServerProxy("http://localhost:8000/RPC2")
print dev.add.numbers(4,6)

私の質問:私の問題を解決する方法、つまり、サーバーまたはクラスDeviceProxy.__getattr__を変更せずに、呼び出された関数、すべての引数などを正しくラップ/上書きできるようにする方法は?xmlrpcDeviceProxy

4

1 に答える 1

0

ここには 2 つの問題があります。

  1. DeviceProxy のすべての属性は機能しますか? そうでない場合は、オブジェクトが期待されているときに関数を返すことがあります
  2. 関数をラップする場合、メンバー間でコピーすることはありません -functools.wrapsそれを達成するために使用します。

これはうまくいくはずです

from functools import wraps

@wraps(original)  # probably not needed, but sensible
def mygetattr(device, key):
    attr = original(device, key)
    if callable(attr):
        @wraps(attr)  # copy across __name__, __dict__ etc
        def wrapper(*args, **kw):
            print('called with %r and %r' % (args, kw))
            return attr(*args, **kw)
        return wrapper
    else:  # handle (or rather, don't) non-callable attributes
        return attr
于 2012-12-08T13:35:17.763 に答える