在类上调用任意方法,如xmlrpclib.ServerProxy

时间:2017-07-25 23:32:12

标签: python xmlrpclib

我有一个远程api只接受可以被称为

的XML
api = xmlrpclib.ServerProxy(IP)
result = api.Execute({"Method": 'Method_name', "Params": [P1, P2],
                      ...  # technical values - authentication, etc
                      })

技术值不会经常变化 - 整个脚本通常会使用相同的值,所以我创建了一个具有方法的类

def call(self, method_name, params):
    self.api.Execute(<constructed dictionary>)

我想知道是否可以直接将这些方法称为self.api的方法:

self.api.method_name(params)

反过来会为.Execute填写其余部分,其余部分为:

def __getattr__(self, item):
    if item in self.__dict__:
        return self.item
    else:
        return functools.partial(self.call, method_name=item)

所以,如果我在课堂上定义了一个方法(self.fooself.bar等) - 调用它会产生self.fooself.bar的真实结果。

将其称为self.api.METHOD(params) METHOD,其中self.api.__repr__是自定义的,但这种做法会污染&#34;我没有定义的其他方法,如__getitem__

根据this question,我的覆盖date1 = new Date(fDates[i, 0]) date2 = new Date(fDates[i+1, 0]) if (date2 < date1) { // or whatever comparison you want ... // flag / print / alert the date } 的方法是否完全错误,这是真的吗?如果是这样 - 我该如何实现呢?

1 个答案:

答案 0 :(得分:1)

我最近看了a talk by Raymond Hettinger这篇帖子松散提醒的内容,所以我想我会链接到它。我认为这对你在帖子中描述的方法提出了很好的论据:

让API为您服务

首先,我不认为压倒__getattr__就像你可能相信的帖子那样有罪。

class MyAPI(object):
  base_args = {'token': 'foobarauthtoekn'}

  def __init__(self, ip):
    self._api = ServerProxy(ip)

  def _execute(self, method='', **kwargs):
    argdict = {'Method': method}
    argdict.update(MyAPI2.base_args)
    argdict.update(kwargs)
    self._api.Execute(argdict)

  def __getattr__(self, attr):
    return self.__dict__.get(
      attr, partial(self._execute, method=attr))


api = MyAPI('127.0.0.1')

# Execute({'token': ..., 'Method': 'get_users', 'arg1': 'foo' ...}) =
api.get_users(arg1='foo', arg2='bar')

# Execute({'token': ..., 'Method': 'get_data', 'foo': 'stuff' ...}) =
api.get_data(foo='stuff', bar='zxcv')

我喜欢这个,因为它不是很多代码,它让我们以更方便的方式使用Execute(使用关键字args),而不依赖于内部API的支持。

通过元类的特殊行为

另一种方法阻止我们不得不覆盖__getattr__,以防我低估了它的错误程度,并且它也可以被认为是更加pythonic,因为我们明确列举了我们的方法。 ;将提供我们的API包装器:

class APIMeta(type):
  def __new__(cls, clsname, bases, attrs):

    def exec_generic(name):
      base_args = {'token': 'foobarauthtoekn'}
      def exec_wrapper(self, params):
        args = {'Method': name}
        args.update(base_args)
        args.update(params)
        return self._api.Execute(args)
      return exec_wrapper

    new_attrs = {
      name: val if name.startswith('__') else exec_generic(name)
      for name, val in attrs.items() }

    return super(APIMeta, cls).__new__(cls, clsname, bases, new_attrs)

class MyAPI(object, metaclass=APIMeta):
  def __init__(self, ip):
    self._api = ServerProxy(ip)

  def get_users(self):
    pass

  def get_data(self):
    pass

  # ...

实际上,我不喜欢这样,因为它只是一种非常错综复杂的写作方式:

class MyAPI(object):
  _base_args = {'token': 'foobarauthtoken'}

  def __init__(self, ip):
    self._api = ServerProxy(ip)

  def get_users(self, params):
    argdict = {'Method': 'get_users'}
    argdict.update(MyAPI._base_args)
    argdict.update(params)
    return self._api.Execute(argdict)

  # ...

如果您有很多方法,它会为您节省大量的打字工作,如果您希望深入了解或深入理解,那么它也是元编程的好习惯。 python语言。

Here's同时演示。