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包装了代理,通过方法转发任意调用。由于此问题范围之外的其他原因,我需要用不同的方法包装/替换此方法,例如打印出调用的函数的名称、参数等(请参阅此处的相关问题)。xmlrpc__getattr____getattr__

但是这种方法不起作用,它给出了以下错误:

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

该示例按预期工作,当我

  • 不要DeviceProxy.__getattr__用别的东西代替
  • 替换DeviceProxy.__getattr__为函数

    def dummy(实例,属性):返回原始(设备,属性)

  • xmlrpc用零点名称替换函数的名称(例如,只是sum代替sum.numbers

您可以验证自己通过 xmlrpc 代理进行的以下直接调用将按预期工作:

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

我的问题:如何解决我的问题,即如何能够DeviceProxy.__getattr__正确地包装/覆盖以便能够看到调用的函数、所有参数等,而无需在xmlrpc服务器或DeviceProxy类中进行更改?

4

1 回答 1

0

我可以在这里看到两个问题:

  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 回答