2017-07-25 39 views
1

我有一个远程API接受个XML只可以被称为像调用任意方法,如xmlrpclib.ServerProxy

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__和类似

其他方法这是真的,根据我的this question的方法重写__getitem__完全不正确?如果是这样 - 我应该如何执行此操作?

+0

'Execute'是单个字典还是一系列关键字参数?第一块中的代码似乎表示前者,但您调用“partial”的方式表示后者。此外,是一个暴露给脚本的可用'Execute'方法的综合列表? – Will

+0

@wilusdaman,它实际上需要一个字典。使用'partial'的方式是因为有间歇性的内部和外部方法来构造这个字典并且对它的值进行操作。综合列表不幸的是不可用。 – RebelWithoutAPulse

回答

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(用关键字参数),不依赖于的支持,以便从内部API。

通过元类特殊行为

另一种方法使我们不必重写__getattr__的情况下,我低估了多少错误是的,它也可以被认为是更Python,因为我们明确地列举我们将与我们的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这两个演示。

+0

非常感谢。这确实在这一点上纯粹是一个练习问题,我很想找到一些元类的应用程序。我会尝试这些建议,一旦他们适合,将接受答案,如果你不介意。 – RebelWithoutAPulse

相关问题