2009-07-07 10 views
1

Beispiel:Elegante Möglichkeit, mehrere Funktionsaufrufe zu abstrahieren?

>>> def write_to_terminal(fmt, *args): 
...  print fmt % args 
>>> LOG = logging.getLogger(__name__) 
>>> info = multicall(write_to_terminal, LOG.info) 
>>> debug = multicall(write_debug_to_terminal, LOG.debug) 
>>> ... 
>>> info('Hello %s', 'guido') # display in terminal *and* log the message 

Gibt es eine elegante Art und Weise multicall zu schreiben? Vielleicht mit Hilfe der Standardbibliothek .. ohne das Rad neu zu erfinden?

+0

Warum tue ich das? Weil ich ein separates Modul geschrieben habe (nennen Sie es "ui.py"), das auf die Konsole schreibt ... und auch die Protokollierung verwendet, um Dinge zu protokollieren. Häufig wird die Nachricht, die auf der Konsole ausgegeben werden soll, ebenfalls protokolliert. –

+1

Sie können das Logging-Modul dafür konfigurieren. Verwenden Sie einfach mehrere Handler und/oder Logger mit entsprechenden Ebenen. –

+0

Logging-Modul ist nicht für textuelle UI .. Interaktion mit dem Benutzer konzipiert. zB: write_to_terminal könnte mit einem bereits angezeigten Fortschrittsbalken interagieren und ihn sogar verstecken (nur bzr tut das) –

Antwort

5

So ähnlich?

def multicall(*functions): 
    def call_functions(*args, **kwds): 
     for function in functions: 
      function(*args, **kwds) 
    return call_functions 

Und wenn Sie die Ergebnisse aggregieren möchten:

def multicall(*functions): 
    def call_functions(*args, **kwds): 
     return [function(*args, **kwds) for function in functions] 
    return call_functions 

EDIT

Zierer wurden vorgeschlagen; in diesem Fall würde es so aussehen:

def appendcalls(*functions): 
    def decorator(decorated_function): 
     all_functions = [decorated_function] + list(functions) 
     def call_functions(*args, **kwds): 
      for function in all_functions: 
       function(*args, **kwds) 
     return call_functions 
    return decorator 


LOG = logging.getLogger(__name__) 

@appendcalls(LOG.info) 
def info(fmt, *args): 
    print fmt % args 

info('Hello %s', 'guido') 

appendcalls() nimmt eine beliebige Anzahl von Funktionen nach der dekorierten Funktion aufgerufen werden. Sie möchten den Decorator möglicherweise anders implementieren, je nachdem, welchen Rückgabewert Sie wünschen - das Original aus der dekorierten Funktion, eine Liste aller Funktionsergebnisse oder gar nichts.

+0

Es scheint, dass selbst 'functools' nicht dabei helfen, das selbst zu schreiben. –

+0

Eigentlich möchte ich die ursprüngliche 'info' (' write_to_terminal' in meinem Beispiel) behalten und die neue Information (die auch LOG aufruft) * zusätzlich zu * der bestehenden Version, die LOG nicht aufruft, bereitstellen. '@ appendcalls' behält die ursprüngliche Funktion nicht bei. Zum Beispiel möchte ich keine Funktion an eine andere "anhängen". Sondern eine * neue * Funktion erstellen, die N andere Funktionen aufruft, die dieselben Argumente übergeben. –

+0

@snd, in diesem Fall können Sie keinen Decorator verwenden (der per definitionem den Namen der Funktion, die er dekorieren soll, neu zuweist!), Und @ Steefs erster Teil der Antwort (vor dem Edit :) ist, was Sie suchen. Und yep, functools bietet nicht diesen selten benötigten, einfach zu schreibenden HOF (noch eine Billion andere!) –

Verwandte Themen