将多个函数包含在同一个语句中的pythonic方法是什么?

时间:2012-09-03 16:51:12

标签: python eval fabric with-statement contextmanager

我正在使用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的每一页都表明,由于安全问题,这几乎总是一个坏主意。我调查了部分内容,但我无法弄清楚如何在我的_mute函数中调用参数。我猜这里有一个更高级别的Python概念,我在这里缺少。做这个的pythonic方法是什么?感谢您提供的任何方向。

1 个答案:

答案 0 :(得分: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?