简体   繁体   English

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

[英]What's the pythonic way to wrap several functions in the same with statements

I am using the Python library, Fabric , to do some remote server maintenance. 我正在使用Python库Fabric来进行一些远程服务器维护。 Fabric automatically outputs all of the responses to remote and local commands unless you wrap the command in a couple with statements. Fabric会自动输出对远程和本地命令的所有响应,除非您将命令包装在一对语句中。 Like so, on a local machine, 像这样,在本地机器上,

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

or like this on a remote machine: 或者像这样在远程机器上:

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

I am writing a long and complex task and find myself repeating those two with statements over and over again. 我正在写一个漫长而复杂的任务,并发现自己一遍又一遍地重复这两个。 I want to write a function called _mute() to prevent that repetition. 我想编写一个名为_mute()的函数来防止重复。 It would let me do something like this: 它会让我做这样的事情:

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)

I've looked into some solutions and know that "eval" could do this for me. 我已经研究了一些解决方案并且知道“eval”可以为我做这件事。 But every page I read about eval suggests that it's almost always a bad idea because of security issues. 但是我读到的关于eval的每一页都表明,由于安全问题,这几乎总是一个坏主意。 I looked into partials, but I couldn't figure out how to make an argument in my _mute function callable. 我调查了部分内容,但我无法弄清楚如何在我的_mute函数中调用参数。 I'm guessing there's a higher level Python concept I'm missing here. 我猜这里有一个更高级别的Python概念,我在这里缺少。 What's the pythonic way to go about doing this? 做这个的pythonic方法是什么? Thanks for any direction you might be able to provide. 感谢您提供的任何方向。

The better solution would be for you to build your own context manager; 更好的解决方案是建立自己的上下文管理器; by far the easiest way would be to use the contextlib.contextmanager decorator : 到目前为止最简单的方法是使用contextlib.contextmanager装饰器

from contextlib import contextmanager

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

Then use _mute as a context manager: 然后使用_mute作为上下文管理器:

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

This is a lot more compact and readable than having to retype the two larger context manager lines and has the added advantage that now you can run multiple commands in that same context. 这比必须重新键入两个更大的上下文管理器行更加紧凑和可读,并且具有额外的优势,即现在可以在同一上下文中运行多个命令。

As for your question; 至于你的问题; you can easily apply arbitrary arguments to a given function using the *args syntax: 您可以使用*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')

See *args and **kwargs? * args和** kwargs? for more information on the *args arbitrary argument lists tricks. 有关*args任意参数列表技巧的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM