2012-09-03 46 views
6

我正在使用Python庫Fabric來做一些遠程服務器維護。除非您將命令包含在一對語句中,否則Fabric會自動將所有響應輸出到遠程命令和本地命令。像這樣,在本地機器上,什麼是用幾個函數包裝幾個函數的語句方式

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

或像這樣在遠程機器上:

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

我寫一個長期而複雜的任務,發現自己重複那兩個用一遍又一遍聲明。我想寫一個名爲_mute()的函數來防止重複。它會讓我做這樣的事情:

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) 

我已經研究了一些解決方案,並知道「eval」可以爲我做這個。但是我讀到的關於eval的每一頁都表明,由於安全問題,它幾乎總是一個壞主意。我研究了partials,但我無法弄清楚如何在我的_mute函數中調用一個參數。我猜這裏有一個更高級別的Python概念。這樣做的pythonic途徑是什麼?感謝您可能提供的任何方向。

回答

11

更好的解決方案將是你建立你自己的上下文管理器;迄今爲止最容易的方法是使用contextlib.contextmanager decorator

from contextlib import contextmanager 

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

然後用_mute作爲上下文經理:

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

這是一個很多比重新鍵入兩個較大的背景下更緊湊和可讀性經理線,並已增加的優勢,現在你可以在同一個上下文中運行多個命令。

至於你的問題;您可以輕鬆地使用*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') 

有關*args任意參數的更多信息,請參見*args and **kwargs?列出的招數。

+0

感謝@contextmanager裝飾工作完美。我很感謝你指導我對那些文檔以及* args語法。 –