恢复重定向的sys.stdout和sys.stderr,产生奇怪的结果

时间:2017-08-04 22:11:11

标签: python io-redirection

在查看其他stackoverflow帖子后,我似乎无法解决此重定向问题。我想要做的是抑制stdoutstderr,然后在捕获错误后恢复它们。镇压工作正常,但恢复他们只有一半工作。

如果我尝试抑制并恢复stderrstdout,则抑制有效但无法恢复。如果我只是尝试压制/恢复stdout它可以正常工作(但我会收到我不想要的所有stderr文字)。

我无法推断为什么导致stderr阻止stdout被恢复会有任何差异,希望能够输入原因(或者如果我是做一些奇怪/愚蠢的事情

这里是我想要工作的代码,但只是抑制了/错误并且没有恢复('Restored stdout'从不打印):

sys.stdout = None
sys.stderr = None
try:
    op_args = op_parse.parse_args(selection.split(' '))
except SystemExit:
    sys.stdout = sys.__stdout__
    sys.stderr = sys.__stderr__
    print("Restored stdout")

以下代码禁止stdout并恢复它(以打印讨厌的stderr为代价):

sys.stdout = None
#sys.stderr = None
try:
    op_args = op_parse.parse_args(selection.split(' '))
except SystemExit:
    sys.stdout = sys.__stdout__
    #sys.stderr = sys.__stderr__
    print("Restored stdout")

编辑:我找到了解决方法,但我仍然对上述问题发生的原因感兴趣。我的解决方法是将stdout / stderr重新分配给= open("/dev/null", "w"),这会产生我想要的行为。我仍然希望输入原始问题。

2 个答案:

答案 0 :(得分:3)

通过创建上下文管理器,您可以更优雅地完成此任务:

import os
from contextlib import contextmanager

@contextmanager
def nullout():
    save_stdout = sys.stdout
    save_stderr = sys.stderr
    sys.stdout = open(os.devnull, 'w')
    sys.stderr = open(os.devnull, 'w')
    try:
        yield
    finally:
        sys.stdout = save_stdout
        sys.stderr = save_stderr

with nullout():
    op_args = op_parse.parse_args(selection.split(' '))

关于上下文管理器的一个好处是,yield之后的代码将被执行,无论是否发生异常。

您不能将sys.stdoutsys.stderr设置为None的原因可能是因为None没有write()或{{1方法,通常不像输出流。

答案 1 :(得分:0)

作为一个高级评论,这种技术容易出错,通常意味着其他问题出错。例如 - 在except上方(而不是在finally中)进行恢复意味着如果失败则还原stdout和仅stderr

我怀疑您观察到的问题可能是由于op_parse调用造成的。请考虑以下代码

from __future__ import print_function
import sys

sys.stdout = None
sys.stderr = None
try:
    print('before', file=sys.stdout)
    print('before', file=sys.stderr)
    # sys.stderr.write('hi')
    assert False
except AssertionError:
    sys.stdout = sys.__stdout__
    sys.stderr = sys.__stderr__
    print("Restored stdout", file=sys.stdout)

当我运行它时,我看到:Restored stdout

如果我取消注释sys.stderr.write行,我会看到:lost sys.stderr

更安全的方法是在操作期间使用上下文将stdout / err重定向到/dev/nullIOStream - 或者更好的是,找到内部使用的验证函数并直接调用它在高级函数上寻找系统退出(op_parse == opt_parse?)

相关问题