Python 包装对xmlrpc服务器的函数调用

Python 包装对xmlrpc服务器的函数调用,python,attributes,xml-rpc,Python,Attributes,Xml Rpc,我有一个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

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

但这种方法不起作用,它会产生以下错误:

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

  • 不要用其他东西替换设备代理
  • 用函数替换设备代理

    def虚拟(实例,属性): 返回原件(设备、属性)

  • xmlrpc
    函数的名称替换为零点名称(例如,仅
    sum
    而不是
    sum.numbers

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

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

我的问题:如何解决我的问题,即如何能够正确地包装/覆盖
DeviceProxy.\uu getattr\uuu
以便能够在不更改
xmlrpc
服务器或
DeviceProxy
类的情况下查看调用的函数、所有参数等。

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

  • DeviceProxy的所有属性都是函数吗?如果不是,那么您有时会在需要对象时返回函数
  • 当您包装函数时,您不会跨成员进行复制-请使用
    functools.wrapps
    来实现这一点
  • 这应该行得通

    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
    

    你的观点(1)是一个有效的观点,我仍然需要看一看第(2)点。使用您的代码,我不再得到任何错误,但也没有任何输出!我只是打印了号码
    10
    ,但没有打印我要的其他信息。也许我忘了什么,请发布完整的代码好吗?当我再次使用你的代码发布DeviceProxy时,我得到一个错误
    回溯(最近一次调用):文件“code.py”,第50行,在打印dev.add.numbers(4,6)文件“code.py”,第22行,在mygetattr@wrapps(attr)中#在update#u wrapper setattr(wrapper,attr,getattr(wrapper,attr))TypeError中的第33行,复制"名称","目录"等文件/usr/lib/python2.7/functools.py:"名称"必须设置为字符串对象
    @Alex:如果添加
    打印属性,会得到什么,attr.\uuuu name\uuuuuu
    就在这之前?您的额外信息不会被打印,因为
    DeviceProxy.\uuu getattr\uuuuuu
    是为
    x=dev.add
    调用的,而不是为
    x.numbers
    调用的,那么我如何解决这个问题呢?如您所见,
    xmlrpc
    服务器对函数的调用方式有一些定义,它们可以是
    add
    add.numbers
    add.numbers.max
    或其他任何形式。我无法控制
    xmlrpc
    服务器中的命名,但需要打印出确切的调用内容。