我使用基于os.dup2的策略(类似于此站点上的示例)将C / fortran级别输出重定向到临时文件以进行捕获。
我唯一注意到的问题是,如果你从windows中的交互式shell(python.exe或ipython)中使用此代码,它会在控制台中启用启用输出缓冲的奇怪副作用/ em>的
捕获之前sys.stdout
是某种为True
返回istty()
的文件对象。键入print('hi')
会导致hi直接输出。
捕获后sys.stdout
指向完全相同的文件对象,但print('hi')
在调用sys.stdout.flush()
之前不再显示任何内容。
下面是一个最小的示例脚本" test.py"
import os, sys, tempfile
class Capture(object):
def __init__(self):
super(Capture, self).__init__()
self._org = None # Original stdout stream
self._dup = None # Original system stdout descriptor
self._file = None # Temporary file to write stdout to
def start(self):
self._org = sys.stdout
sys.stdout = sys.__stdout__
fdout = sys.stdout.fileno()
self._file = tempfile.TemporaryFile()
self._dup = None
if fdout >= 0:
self._dup = os.dup(fdout)
os.dup2(self._file.fileno(), fdout)
def stop(self):
sys.stdout.flush()
if self._dup is not None:
os.dup2(self._dup, sys.stdout.fileno())
os.close(self._dup)
sys.stdout = self._org
self._file.seek(0)
out = self._file.readlines()
self._file.close()
return out
def run():
c = Capture()
c.start()
os.system('echo 10')
print('20')
x = c.stop()
print(x)
if __name__ == '__main__':
run()
打开命令提示符并运行脚本可以正常工作。这会产生预期的输出:
python.exe test.py
从python shell运行它不会:
python.exe
>>> import test.py
>>> test.run()
>>> print('hello?')
直到刷新stdout才会显示输出:
>>> import sys
>>> sys.stdout.flush()
有人知道发生了什么吗?
快速信息:
答案 0 :(得分:2)
我可以确认Linux中的Python 2的相关问题,但不能用Python 3确认
基本问题是
>>> sys.stdout is sys.__stdout__
True
因此,您始终使用原始sys.stdout
对象 。当您执行第一次输出时,在Python 2中,它会对基础文件执行一次isatty()
系统调用,并存储结果。
您应该打开一个全新的文件并用它替换sys.stdout
。
因此,编写Capture
类的正确方法是
import sys
import tempfile
import time
import os
class Capture(object):
def __init__(self):
super(Capture, self).__init__()
def start(self):
self._old_stdout = sys.stdout
self._stdout_fd = self._old_stdout.fileno()
self._saved_stdout_fd = os.dup(self._stdout_fd)
self._file = sys.stdout = tempfile.TemporaryFile(mode='w+t')
os.dup2(self._file.fileno(), self._stdout_fd)
def stop(self):
os.dup2(self._saved_stdout_fd, self._stdout_fd)
os.close(self._saved_stdout_fd)
sys.stdout = self._old_stdout
self._file.seek(0)
out = self._file.readlines()
self._file.close()
return out
def run():
c = Capture()
c.start()
os.system('echo 10')
x = c.stop()
print(x)
time.sleep(1)
print("finished")
run()
使用这个程序,在Python 2和Python 3中,输出将是:
['10\n']
finished
第一条线瞬间出现在终端上,第二条线在一秒钟后出现延迟。
但是,对于从stdout
导入sys
的代码,这会失败。幸运的是没有多少代码可以做到这一点。