Monthly Archives: March 2016

zerorpc通用Client实例直接调用特定server RPC方法原理

假设server端代码定义了一个RPC方法hello

import zerorpc
class HelloRPC(object):
    def hello(self, name):
        return "Hello, %s" % name

s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()

在客户端代码如果要调用只需简单新建一个Client实例,然后直接以client.hello()调用。

import zerorpc
client = zerorpc.Client()
client.connect("tcp://127.0.0.1:4242")
print client.hello("RPC")

Client作为一个通用类,并未定义def hello(name):方法,直接以client.hello()调用是怎么做到的?答案就是利用了python的__getattr____call__,关键代码如下。

class Client(object):
    def __init__(self, ):
        pass

    def __call__(self, method, *args, **kwargs):
        # 在这连接server,序列化参数,请求,反序列化响应数据,并return
        pass

    def __getattr__(self, method):
        # 返回一个闭包,该闭包封装了self和method.
        # 当这个闭包被执行时,即x(*args, **kwargs),
        # 即self(method, *args, **kargs)被运行,
        # 即self.__call__(self, method, *args, **kwargs)
        f = lambda *args, **kwargs: self(method, *args, **kwargs)
        return f

当执行client.hello('RPC')时,会分两步,先获取hello这个属性的值,然后调用这个值。即先调用client.__getattr__('hello')查询hello这个属性的值,得到f,而f是一个闭包函数,然后调用f('RPC')