2012-09-03 9 views
6

Sto utilizzando la libreria Python, Fabric, per eseguire la manutenzione del server remoto. Fabric restituisce automaticamente tutte le risposte ai comandi remoti e locali, a meno che non si completi il ​​comando in un paio di istruzioni. Come così, su un computer locale,Qual è il modo pitone per racchiudere più funzioni nello stesso con le affermazioni

with settings(warn_only='true'): 
    with hide('running', 'stdout', 'stderr', 'warnings'): 
     output = local("uname -a", True) 

o come questo su una macchina remota:

with settings(warn_only='true'): 
    with hide('running', 'stdout', 'stderr', 'warnings'): 
     output = run("uname -a") 

Sto scrivendo un compito lungo e complesso e mi ritrovo a ripetere quei due con le dichiarazioni più e più volte . Voglio scrivere una funzione chiamata _mute() per evitare quella ripetizione. E mi permetteva di fare qualcosa di simile:

def _mute(fabric_cmd, args): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      output = fabric_cmd(args) 
    return output 

def some_remote_task(): 
    # Run a remote task silently 
    _mute(remote, 'uname -a') 

def some_local_task(): 
    # Run a local task silently 
    _mute(local, 'uname -a', True) 

Ho esaminato alcune soluzioni e so che "eval" potrebbe fare questo per me. Ma ogni pagina che ho letto su eval suggerisce che è quasi sempre una cattiva idea a causa di problemi di sicurezza. Ho esaminato i partial, ma non sono riuscito a capire come risolvere un argomento nella mia funzione _mute callable. Immagino che ci sia un concetto Python di livello superiore che mi manca qui. Qual è il modo pitonioso per fare questo? Grazie per ogni direzione che potresti essere in grado di fornire.

risposta

11

La soluzione migliore sarebbe creare il proprio gestore di contesto; di gran lunga il modo più semplice sarebbe quella di utilizzare il contextlib.contextmanager decorator:

from contextlib import contextmanager 

@contextmanager 
def _mute(): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      yield 

Quindi utilizzare _mute come contesto allenatore:

def some_remote_task(): 
    # Run a remote task silently 
    with _mute(): 
     output = remote("uname -a") 

Questo è molto più compatto e leggibile di dover digitare nuovamente il contesto due più grandi linee gestore e ha il aggiunto vantaggio che ora è possibile eseguire più comandi nello stesso contesto.

Come per la domanda; si può facilmente applicare argomenti arbitrari ad una determinata funzione utilizzando la sintassi *args:

def _mute(fabric_cmd, *args): 
    with settings(warn_only='true'): 
     with hide('running', 'stdout', 'stderr', 'warnings'): 
      return fabric_cmd(*args) 

def some_remote_task(): 
    # Run a remote task silently 
    output = _mute(remote, 'uname -a') 

Vedi *args and **kwargs? per ulteriori informazioni sull'argomento arbitraria *args elenca trucchi.

+0

Grazie al decoratore @contextmanager ha funzionato perfettamente. Apprezzo che tu mi abbia guidato verso i documenti per quelli così come la sintassi * args. –

Problemi correlati