2016-06-15 4 views
1

Ich habe eine Python-Funktion „send_message“, die drei Argumente verwendet:Fluent Interface mit Python

send_message("i like windmills", to="INBOX", from="OUTBOX") 

Ich denke an eine fließend Schnittstelle oben drauf setzen. Im Idealfall würde Ich mag folgendes schreiben:

send_message("i like windmills").to("INBOX").from("OUTBOX") 

oder

send_message("i like windmills").from("OUTBOX").to("INBOX") 

Update: Die to() Informationen ist obligatorisch, aber die from() ist nicht (wie bei echten Buchstaben). Also wäre dieser auch ein gültiger Anruf:

send_message("i like windmills").to("INBOX") 

Irgendwelche Ideen, wie man dies oder etwas ähnliches erreicht?

Der allgemeine Ansatz von Methoden eines Objekts mit „Selbst“ Rückkehr wird von mir verstanden, aber in meinem Verständnis, dies zu so etwas wie dies führen würde:

message = Message("i like windmills") 
message.to("INBOX").from("OUTBOX").send() 

Aber das ist nicht so schön wie die vorherige Beispiel und ich würde dann eigentlich die Originalversion mit den genannten Argumenten vorziehen.

Jede Hilfe wird geschätzt.

+0

Sie möchten das [Builder Pattern] (https://en.wikipedia.org/wiki/Builder_pattern) implementieren. 'send_message' wäre die Factory-Methode zum Erstellen des Builders. –

+1

Alternativ könnten Sie [currying] (https://en.wikipedia.org/wiki/Currying) implementieren; es vermeidet das Objekt "Overhead", das offensichtlich vom OP nicht gewünscht wird. –

+0

Hallo Lutz, nicht ganz. Das Builder-Muster erfordert eine letzte "build()" -Methode in der Kette, um die Aktion tatsächlich auszuführen. Ich hatte gehofft, einen Weg zu finden, dass jede Methode in der Kette erkennen kann, ob es die letzte ist (durch Meta-Programmierung?). Wenn dies der Fall ist, führt es die Aktion implizit aus. – samba2

Antwort

2

Es kann auf diese Weise erreicht werden, ich bin mir nicht sicher, ob es einen besseren Weg gibt, weil dies mein erster Versuch ist. Viel Glück!

DEFAULT_SENDER = 'my_address' 
#Because the sender object is optional I assume you have a default sender 

class Send_message(object): 
    def __init__(self, message): 
     self.message = message 
     self.sender = None 
     self.reciever = None 
     self.method = None 

    def to(self, reciever): 
     self.reciever = reciever 
     self.method = self.send() 
     return self 

    def _from(self, sender): 
     self.sender = sender 
     self.method = self.send() 
     return self 

    def __call__(self): 
     if self.method: 
      return self.method() 
     return None 

    def send(self): 
     if self.reciever: 
      if not self.sender: 
       self.sender = DEFAULT_SENDER 

      return lambda:actual_message_code(self.message, self.sender, self.reciever) 


def actual_message_code(message, sender, reciever): 
    print "Sent '{}' from: {} to {}.".format(message, sender, reciever) 



Send_message("Hello")._from('TheLazyScripter').to('samba2')() 
Send_message("Hello").to('samba2')._from('TheLazyScripter')() 
Send_message("Hello").to('samba2')() 

#Only change in actual calling is the trailing() 

Durch die __call__ Verfahren setzen wir das sagen können, wenn wir am Ende der Aufrufkette sind. Dies fügt natürlich den nachfolgenden () Aufruf hinzu. und erfordert, dass Sie den Zeiger auf Ihre tatsächliche Messaging-Methode und Standard-Absendervariable ändern, aber ich denke, dass dies der einfachste Weg wäre, Ihre Ziele zu erreichen, ohne zu wissen, wann die Kette endet.

+0

Hi Lazy Scripter. Ich habe Ihre Antwort gewählt, weil es eine wunderbar einfache Lösung für mein anfängliches Problem ist. Allerdings geht es mit agilen Anforderungen. Sie haben mich auf eine Tatsache hingewiesen, die in meiner ursprünglichen Frage fehlte: Die Methode 'to()' ist obligatorisch, während die Methode 'from()' optional ist. Da deine Idee auf den Geschenken der beiden Eigenschaften "Sender" und "Empfänger" beruht, gehe ich davon aus, dass es nicht funktionieren wird. – samba2

+0

Ich habe meinen Code aktualisiert, um Ihre aktualisierten Parameter anzupassen. – TheLazyScripter