0

我有一个 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 并没有对我大喊大叫,但我仍然不禁觉得它不是太 Pythonic,而且我不完全确定它是否安全。我正在向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
4

1 回答 1

0

选择性地重定向程序stdoutstderr文件的最简洁方法是根本不在程序中这样做。相反,通过操作系统的外壳来完成。

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

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

注意2>重定向stderr输出。

碰巧, Windows 上cmdPowerShell使用相同的语法。


鉴于 OP 更新的问题描述,上述内容虽然属实,但并不相关。

假设您使用的是 Python 3,内置print函数实际上有一个命名参数“ file”,可以让您决定去哪里print

print(some_object, file=your_own_file_object)

file可以是任何类似文件的对象(whichstdoutstderrare)。您可以只传递结果open(),或者发疯并乱搞io模块。无论如何,您只需要维护一个变量(其值可能是 的sys.stdout)并始终将其传递给print调用,然后在您决定将某些内容输出到何处时只需设置该变量即可。

否则,如果您不介意从其他 Python 程序员那里得到有趣的表情,您可能会考虑设置sys.stdoutand的值。sys.stderr

于 2015-10-22T22:39:34.387 回答