2017-07-25 2 views
1

ich eine Remote-api haben zu akzeptieren XMLs nur das kann wieAufruf beliebige Methoden auf Klasse wie xmlrpclib.ServerProxy

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

Die technischen Werte unterliegen nicht aufgerufen werden häufig ändern - ganze Skript in der Regel dieselben Werte verwenden würde für sie, so habe ich eine Klasse, die eine Methode hat

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

ich mich gefragt, ob es möglich wäre, diese Methoden direkt als Methoden der self.api wie zu nennen:

self.api.method_name(params) 

was wiederum würde für mich in den .Execute und den Rest füllen, mit dem allgemeinen Gedanken wie:

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

Also, wenn ich eine Methode in der Klasse definiert (self.foo, self.bar und dergleichen) - Aufruf es würde echte Ergebnisse von self.foo und self.bar ergeben.

aufrufen es wie self.api.METHOD(params) wo METHOD ist ein Brauch man arbeitet, aber dieser Ansatz „verpestet“ andere Methoden, die ich nicht definieren, wie self.api.__repr__ und dergleichen

Stimmt es, dass nach this question mein Ansatz von überschreiben __getitem__ ist völlig falsch? Wenn ja - wie soll ich das umsetzen?

+0

Nimmt 'Execute' ein einzelnes Wörterbuch oder eine Reihe von Schlüsselwörtern? Der Code im ersten Block scheint den ersten anzuzeigen, aber die Art, wie Sie "partially" aufrufen, zeigt Letzteres an. Gibt es auch eine umfassende Liste verfügbarer 'Execute'-Methoden, die dem Skript ausgesetzt sind? – Will

+0

@wilusdaman, es dauert effektiv ein einzelnes Wörterbuch. Die Art "partiell" wird verwendet, weil intermittierende interne und externe Methoden dieses Wörterbuch konstruieren und mit seinen Werten arbeiten. Die umfassende Liste ist leider nicht verfügbar. – RebelWithoutAPulse

Antwort

1

Ich habe mir kürzlich a talk by Raymond Hettinger angeschaut, woran dieser Beitrag nur noch erinnert, also dachte ich, ich würde mich damit verbinden. Ich denke, es ist ein großes Argument für den Ansatz, den Sie in die Sie beschrieben schreiben:

die Arbeit API für Sie

Zunächst einmal glaube ich nicht zwingende __getattr__ als diese Stelle als sündig ist Macht hast du es glauben.

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') 

Ich mag das, weil es nicht viel Code ist, und es lässt uns Execute auf eine bequemere Weise nutzen (mit Stichwort args), ohne von der internen API für die auf Unterstützung angewiesen zu sein.

Sonder Verhalten über metaclasses

Der andere Ansatz hindert uns __getattr__ falls außer Kraft zu setzen, die ich habe unterschätzt, wie viel von einem Fehler es ist, und es könnte auch mehr pythonic betrachtet werden, da wir explizit aufzählen die Methoden, die wir mit unserem API-Wrapper zur Verfügung stellen würden:

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 

    # ... 

In Wirklichkeit ich mag das nicht, da es wenig mehr ist als ein sehr gewundener Weg zu schreiben:

obwohl haben, und es ist auch eine gute Praxis in Meta-Programmierung
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) 

    # ... 

Es wird Ihnen eine beträchtliche Menge der Eingabe sparen, wenn Sie eine Menge von Methoden, wenn Sie schauen in das bekommen oder Ihr Verständnis für die Sprache Python vertiefen .

Here's eine Demo mit beiden.

+0

Vielen Dank. Dies ist in der Tat eine reine Frage der Übung, und ich wollte sehr gerne eine Anwendung für Metaklassen finden. Ich werde diese Vorschläge ausprobieren und sobald sie passen, werde ich die Antwort akzeptieren, wenn es Ihnen nichts ausmacht. – RebelWithoutAPulse

Verwandte Themen