2017-07-25 41 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

相關問題