2012-04-03 2 views
1

Ich versuche eine Bibliothek zu schreiben, die eine beliebige Liste von Serviceaufrufen von mehreren Serviceendpunkten in einem Container registriert. Ich beabsichtige, die Serviceaufrufe in Klassen zu implementieren, die pro Dienst einmal geschrieben werden. Gibt es eine Möglichkeit, die Begrenztheit der Methoden von den Serviceklassen beizubehalten, wenn sie beim Container registriert werden (damit sie weiterhin Zugriff auf die Instanzdaten ihrer eigenen Objektinstanz haben), oder muss ich das ganze Objekt registrieren und dann eine Art schreiben von Pass-Through in der Container-Klasse mit __getattr__ oder einige solche für den Zugriff auf die Methoden im Kontext der Instanz?Ist es möglich, "Grenzen" einer Methode beizubehalten, wenn ich sie als Objekt außerhalb ihrer Klasse übergebe

Behälter:

class ServiceCalls(object): 
    def __init__(self): 
     self._service_calls = {} 
    def register_call(self, name, call): 
     if name not in self._service_calls: 
      self._service_calls[name] = call 
    def __getattr__(self, name): 
     if name in self._service_calls: 
      return self._service_calls[name] 

Dienstleistungen:

class FooSvc(object): 
    def __init__(self, endpoint): 
     self.endpoint = endpoint 
    def fooize(self, *args, **kwargs): 
     #call fooize service call with args/kwargs utilizing self.endpoint 
    def fooify(self, *args, **kwargs): 
     #call fooify service call with args/kwargs utilizing self.endpoint 


class BarSvc(object): 
    def __init__(self, endpoint): 
     self.endpoint = endpoint 
    def barize(self, *args, **kwargs): 
     #call barize service call with args/kwargs utilizing self.endpoint 
    def barify(self, *args, **kwargs): 
     #call barify service call with args/kwargs utilizing self.endpoint 

Implementierungscode:

foosvc = FooSvc('fooendpoint') 
barsvc = BarSvc('barendpoint') 
calls = ServiceCalls() 
calls.register('fooize', foosvc.fooize) 
calls.register('fooify', foosvc.fooify) 
calls.register('barize', barsvc.barize) 
calls.register('barify', barsvc.barify) 
calls.fooize(args) 
+0

Diese Frage ist ein bisschen vage. Können Sie ein Codebeispiel hinzufügen? –

+0

Ich habe es noch nicht wirklich geschrieben, ich habe versucht zu bestimmen, ob es überhaupt machbar ist, bevor ich Zeit darin investiere. Ich werde versuchen, etwas illustrational zusammen oben zu hacken, aber ... –

+0

@SvenMarnach, das klärt die Frage ein wenig? Ich dachte daran, jeden Anruf zu einem Objekt zu machen, vielleicht mit den gesamten Servicedaten, dann entweder aufrufbar oder mit einer call() - Methode. Eigentlich, vielleicht werde ich so gehen, da es die Schnittstelle für Anrufbenutzer und Implementierer immer noch sauber lassen wird. –

Antwort

1

Was Sie versuchen zu tun, wird gut funktionieren, wie Sie sehen können, indem Sie Ihren eigenen Code ausführen. :)

Das Objekt foosvc.fooize wird in Python als "gebundene Methode" bezeichnet und enthält sowohl eine Referenz auf foosvc als auch die Funktion FooSvc.fooize. Wenn Sie die gebundene Methode aufrufen, wird der Verweis auf self implizit als erster Parameter übergeben.

Auf eine Randnotiz sollte __getattr__()None für ungültige Attributnamen nicht automatisch zurückgeben. Bessere Verwendung:

def __getattr__(self, name): 
    try: 
     return self._service_calls[name] 
    except KeyError: 
     raise AttributeError 
+0

Oh, es wird funktionieren? Ich dachte, ich erinnere mich daran, dass es nicht funktioniert hat, vorher mit etwas Ähnlichem zu tun zu haben ... und ja, mein tatsächlicher Code versagt nicht im Stillen, ich dachte nur, dass Ausnahmen der aktuellen Frage fremd sind. Ich könnte geschworen haben, eine Methode aus einer Instanz zu übergeben, die eine ungebundene Methode zurückgibt ... na ja. :) Vielen Dank. –

2

Ich denke, das beantwortet Ihre Frage:

In [2]: f = 1 .__add__ 

In [3]: f(3) 
Out[3]: 4 

Sie benötigen die Funktion staticmethod nicht, wenn Sie diese Funktionen zu Klassen hinzufügen, da sie effektiv bereits "statisch" sind.

+2

Gebundene Methoden sind keine Deskriptoren selbst, also brauchst du keine statische Methode. –

+0

'staticmethod' besiegt den Zweck obwohl. Die ganze Idee besteht darin, Zugriff auf Instanzdaten zu haben, was per Definition bei statischen Methoden nicht möglich ist. –

+0

@ sr2222 So funktioniert das nicht. Staticmethod umschließt die übergebene Funktion - sie ändert es nicht magisch, um die Bindung ihres ersten Parameters herauszureißen. – Marcin

1

Ich verstehe den Anwendungsfall dafür nicht - es scheint mir, dass der einfache, einfache, idiomatische Weg, dies zu erreichen, darin besteht, ein Objekt einfach hineinzugeben.

Aber: Programm an die Schnittstelle, nicht die Implementierung. Nehmen Sie nur an, dass das Objekt die Methode hat, die Sie benötigen - berühren Sie nicht die Interna oder andere Methoden.

+0

Das ist die Sache, ich versuche, eine Schnittstelle zu schreiben, die für beide Menschen einfach zu verwenden ist, mit nur einer flüchtigen Bekanntschaft mit, wie Dienste arbeiten und für Leute, die die verfügbare Dienstbibliothek leicht erweitern müssen. Für Ersteres ist die Idee, dass service.foo() den foo-Dienst mit der gesamten Konfiguration und Serialisierung automatisch aufrufen wird, und für den späteren können sie leicht neue Dienstaufrufe für die Schnittstelle registrieren, die die früheren Benutzer verwenden sollen. Der Trick besteht darin, die eingebauten Anrufe effizient und wartungsfreundlich zu strukturieren. –

Verwandte Themen