使用上下文管理器将脚本输出重定向到文件?

发布于 2024-12-21 04:31:19 字数 525 浏览 0 评论 0原文

我正在编写一个脚本,其中有一个选项可以在命令行上传递,无论脚本是否应将其结果打印到标准输出或预定义的结果文件。其代码概要如下所示。我现在已经阅读了一些有关 Python 上下文管理器的内容,但不太确定在这种特定情况下是否以及如何使用上下文管理器。因此,我正在寻求建议,

  1. 在这个问题中使用上下文管理器是否有意义,
  2. 以及如何实施它。

所以,没有上下文管理器的代码是:

option_file = True # would come from OptionParser in real code

if option_file:
    out = open("resultsfile", "w")
else:
    out = sys.stdout

# do some computations
out.write("Results of script")
# more computations and calls to out.write

if option_file:
    out.close()

I'm programming a script where I have an option, to be passed on the command line, whether the script should print its results to stdout or to a predefined results file. A code outline for this is shown below. I now have read a little bit about context managers in Python, but am not really sure whether and how to use a context manager in this specific situation. So I am looking for advice

  1. whether it makes sense to use a context manager in this problem
  2. how to go about implementing it.

So, the code without context manager is:

option_file = True # would come from OptionParser in real code

if option_file:
    out = open("resultsfile", "w")
else:
    out = sys.stdout

# do some computations
out.write("Results of script")
# more computations and calls to out.write

if option_file:
    out.close()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

妞丶爷亲个 2024-12-28 04:31:19

上下文管理器可以与 with 语句一起使用。它的明确设计目的是:

  • 执行一些设置,
  • 给您一个对象,然后
  • 再次执行一些拆卸(即使您引发异常)。

例如,open 可以用作上下文管理器。在下面的代码中,

with open(...) as f:
    # do stuff

无论 stuff 是什么,文件都将始终关闭。 (嗯,通常。除了一些愚蠢的情况,比如电源被关闭或进程被终止。)

当你处于这种情况时,你应该使用上下文管理器。在我看来,它不像你那样,所以我认为没有理由使用上下文管理器。


还有一种使用上下文管理器编写代码的替代方法(没有更好或更坏,只是不同)。如果您想暂时重定向 stdout - 但确保完成后恢复它 - 那么您就处于上述情况。这是一个示例:

@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

然后您可以编写类似的代码

with open(...) as f:
    with redirect_stdout(f):
        # do stuff

,并且对 stuff 中的 stdout 的任何写入都将转至 f


编辑:您是正确的,没有办法有条件地拥有上下文管理器:要么您在其中,要么不在。你总是可以编写自己的,但可能什么也不做:

@contextlib.contextmanager
def maybe_open(path, do_nothing=True):
    if do_nothing:
        f = None
        yield sys.stdout
    else:
        f = open(path)
        yield f

    if f:
        f.close()

这几乎肯定是矫枉过正。

A context manager is something you can use with a with statement. It is explicitly designed to:

  • perform some setup,
  • give you an object, and
  • perform some teardown again (even if you raise an exception).

For example, open can be used as a context manager. In the following code

with open(...) as f:
    # do stuff

it doesn't matter what stuff is, the file will always be closed. (Well, usually. Except in silly cases like the power being turned off or the process being killed.)

You should use a context manager when you are in this sort of situation. It doesn't look to me like you are, so I see no reason for a context manager.


There is an alternative (not better or worse, just different) way of writing your code that does use a context manager. If you want to redirect stdout temporarily -- but ensure that you restore it when you're done -- then you are in the situation above. Here's an example:

@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

You can then write code like

with open(...) as f:
    with redirect_stdout(f):
        # do stuff

and any writes to stdout in stuff will go to f instead.


EDIT: You are correct that there is no way conditionally to have a context manager: either you are in one or you aren't. You could always write your own which might do nothing:

@contextlib.contextmanager
def maybe_open(path, do_nothing=True):
    if do_nothing:
        f = None
        yield sys.stdout
    else:
        f = open(path)
        yield f

    if f:
        f.close()

This is almost certainly overkill.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文