在将stdout重定向到日志文件的同时仍然打印到stdout?

3
我希望能够在Python脚本结束时捕获控制台输出。也就是说,我想要像平常一样打印到控制台,并在执行结束后将控制台输出保存到文件中。
我看过一些相关的SO问题1, 2, 3,但它们要么只是重定向输出而不显示它,要么使用logging。从我阅读loggingdoc得出的结论是,您只能记录您编写的代码的输出。
以上所有链接的问题在于,来自您未编写的代码的控制台输出也会被输出。我想要在执行结束时获取整个程序的控制台输出
我的第一反应是类似于:
logFile = open('LogFile.txt', 'w')
def print_log(msg):
    print(msg)
    logFile.write(msg)

print_log('Hello World!')

logFile.close()

但这仍然无法捕获其他代码和使用的库的控制台输出。 有没有一种方法可以在执行结束时保存Python脚本的控制台输出? 我觉得应该有一种简单的方法来做到这一点,但所有的研究都没有找到合适的解决方案。

你需要用自己的包装器替换sys.stdout,将所有写入其中的内容记录下来并传递到原始的sys.stdout。 - Max Markov
@MaksymMarkov 是的,我认为这是真正的解决方案,这就是我在我的问题中提供代码片段的原因。虽然我希望像这样的东西已经被编写和成熟,或者已经是Python的内置函数。 - KDecker
1个回答

1
我在我的一个项目中使用了这个:

import io
import sys
from enum import Enum


class Tee(io.StringIO):
    class Source(Enum):
        STDOUT = 1
        STDERR = 2

    def __init__(self, clone=Source.STDOUT, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._clone = clone

        if clone == Tee.Source.STDOUT:
            self._out = sys.stdout
        elif clone == Tee.Source.STDERR:
            self._out = sys.stderr
        else:
            raise ValueError("Clone has to be STDOUT or STDERR.")

    def write(self, *args, **kwargs):
        self._out.write(*args, **kwargs)
        return super().write(*args, **kwargs)

    def __enter__(self):
        if self._clone == Tee.Source.STDOUT:
            sys.stdout = self
        else:
            sys.stderr = self
        self.seek(io.SEEK_END)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self._clone == Tee.Source.STDOUT:
            sys.stdout = self._out
        else:
            sys.stderr = self._out
        self.seek(0)
        return False

基本上与Maksym Markov在评论中说的一样,只有一个区别。通常我不想阻塞任何输出,所以我编写了这个Tee,它捕获所有在stdout(或stderr)上进行的文本,立即打印并保存到缓冲区供以后使用。它还负责在代码退出with块时“修复”sys.stdout
使用示例:
if __name__ == "__main__":
    with Tee() as tee:
        print("Hello World!")

    print(tee.read())

有一些缺点,比如在with块内部不能使用tee.read()而不需要额外的代码。但在我的情况下,我总是需要处理整个块的输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接