【问题标题】:Wrapping function calls to xmlrpc server包装对 xmlrpc 服务器的函数调用
【发布时间】:2012-12-08 12:53:05
【问题描述】:

我有一个 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__ 方法,例如打印出被调用函数的名称、参数等(参见相关问题here)。

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

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__ 以便能够查看调用的函数、所有参数等,而无需更改 xmlrpc 服务器或 @ 987654338@上课?

【问题讨论】:

    标签: python attributes xml-rpc


    【解决方案1】:

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

    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
    

    【讨论】:

    • 您的点 (1) 是有效点,我还需要看看点 (2)。使用您的代码,我不再收到错误,但也没有任何输出!我只打印了10 的号码,但没有得到我正在寻找的其他信息。也许我忘记了什么等等,可以发布完整的代码吗?
    • 当我再次使用您的代码执行DeviceProxy.__getattr__ = mygetattr 并执行测试时,我收到错误Traceback (most recent call last): File "code.py", line 50, in <module> print dev.add.numbers(4,6) File "code.py", line 22, in mygetattr @wraps(attr) # copy across __name__, __dict__ etc File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper setattr(wrapper, attr, getattr(wrapped, attr)) TypeError: __name__ must be set to a string object
    • @Alex:如果你在此之前添加一个print attr, attr.__name__,你会得到什么?
    • 不会打印您的额外信息,因为DeviceProxy.__getattr__ 是为x = dev.add 调用的,但不是为x.numbers 调用的
    • 那么我该如何解决这个问题?如您所见,xmlrpc 服务器对函数的调用方式有一些定义,它们可以是addadd.numbersadd.numbers.max 或其他。我对xmlrpc 服务器中的命名没有任何控制权,但需要打印出确切的名称。
    猜你喜欢
    • 2014-05-19
    • 2013-06-22
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 2011-08-05
    • 2011-05-29
    • 1970-01-01
    相关资源
    最近更新 更多