干净且可选地将标准错误或标准输出重定向到文件



我有一个Python3脚本,我想选择性地重定向stdoutstderr到一个文件。像这样:

# variable declarations
if log_output:
    output_file = open('output.txt', 'w')
    sys.stdout = output_file
if log_errors:
    errors_file = open('errors.txt', 'w')
    sys.stderr = errors_file
# code that uses variables declared above but may exit suddenly
#at the end
if log_output:
    output_file.close()
if log_errors:
    errors_file.close()

这是有效的,除非我的代码在中间决定退出。那我的文件就不能保证被关闭了。无论代码中发生了什么,我如何才能干净地关闭这些文件,而且只是在某些时候?(通常,我会通过shell重定向,但我在Python中计算文件名,我不想在不同的shell中重新计算它们。另外,我不想把是否重定向的逻辑放在shell脚本中。如果可能的话,我希望这些分支在我的主代码中。)

尝试1

似乎上下文管理器将是这里的方式,但是,当我尝试使用它们时,我不得不重写我的代码几次,这不是漂亮的代码:

if log_output:
    with open('output.txt', 'w') as output_file:
        with contextlib.redirect_stdout(output_file):
            if log_errors:
                with open('errors.txt','w') as errors_file:
                    with contextlib.redirect_stderr(errors_file):
                        # log_output and log_errors
                        # code that uses variables declared above but may exit suddenly
            else:
                # log_output and not log_errors
                # code that uses variables declared above but may exit suddenly
else:
    if log_errors:
        with open('errors.txt', 'w') as errors_file:
            with contextlib.redirect_stderr(errors_file):
                # not log_output and log_errors
                # code that uses variables declared above but may exit suddenly
    else:
        # not log_output and not log_errors
        # code that uses variables declared above but may exit suddenly

尝试2

我决定为它做一个上下文管理器。我认为它是有效的,Python也没有对我大喊大叫,但我还是忍不住觉得它不太像Python,我也不完全确定它是否安全。我把if的表述往奇怪的方向推了。有没有更好的办法?

@contextlib.contextmanager
def opt_stream(stream, name = None):
    if name:
        file = open(name,'w')
        yield file
        file.close()
    else:
        yield stream
output_name, errors_name = None, None
if log_output:
    output_name = 'outputs.txt'
if log_errors:
    errors_name = 'errors.txt'
with opt_stream(sys.stdout, output_name) as output_file:
    with opt_stream(sys.stderr, errors_name) as errors_file:
        with contextlib.redirect_stdout(output_file):
            with contextlib.redirect_stderr(errors_file):
                # code that uses variables declared above but may exit suddenly

可选地将程序的stdoutstderr重定向到文件的最干净的方法是在程序中根本不这样做。相反,可以通过操作系统的shell来执行。

在Linux上,如果我想将Python程序的stdout重定向到一个文件,我会这样做:

$ python something.py > stdout.log
$ python something_else.py 2> stderr.log

注意重定向stderr输出的2>

碰巧,cmd和PowerShell在Windows上使用相同的语法


上述内容虽然正确,但与OP更新后的问题描述无关。

假设你使用的是Python 3,内置的print函数实际上有一个命名参数" file ",可以让你决定将print放到哪里。

print(some_object, file=your_own_file_object)

file可以是任何类文件对象(stdoutstderr都是)。您可以直接传递open()的结果,或者疯狂地使用io模块。无论哪种情况,您只需要维护一个变量(其值可能是sys.stdout的值)并始终将其传递给print调用,然后在决定将内容输出到何处时设置该变量。

否则,如果您不介意被其他Python程序员嘲笑的话,您可能会考虑设置sys.stdoutsys.stderr的值。

相关内容

  • 没有找到相关文章

最新更新