6

我正在使用 Python 库Fabric进行一些远程服务器维护。Fabric 自动输出对远程和本地命令的所有响应,除非您将命令包装在一对 with 语句中。像这样,在本地机器上,

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 的每一页都表明,由于安全问题,它几乎总是一个坏主意。我研究了部分,但我不知道如何在我的 _mute 函数中创建一个可调用的参数。我猜这里缺少一个更高级别的 Python 概念。这样做的pythonic方法是什么?感谢您提供的任何方向。

4

1 回答 1

11

更好的解决方案是让您构建自己的上下文管理器;到目前为止,最简单的方法是使用contextlib.contextmanager装饰器

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 和 **kwargs?有关*args任意参数列表技巧的更多信息。

于 2012-09-03T16:54:54.463 回答