gpt4 book ai didi

Python os.dup2 redirect 在 Windows python 控制台上启用输出缓冲

转载 作者:太空宇宙 更新时间:2023-11-04 03:35:47 26 4
gpt4 key购买 nike

我正在使用基于 os.dup2 的策略(类似于本网站上的示例)将 C/fortran 级输出重定向到临时文件以进行捕获。

我注意到的唯一问题是,如果您从 Windows 的交互式 shell(python.exe 或 ipython)中使用此代码,它会产生奇怪的副作用,即在控制台中启用输出缓冲.

在捕获之前 sys.stdout 是某种文件对象,它为 istty() 返回 True。输入 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()

有人知道发生了什么事吗?


快速信息:

  • 问题出现在 Windows 上,出现在 linux 上(因此可能不出现在 mac 上)。
  • Python 2.7.6 和 Python 2.7.9 中的行为相同
  • 脚本应该捕获 C/fortran 输出,而不仅仅是 python 输出
  • 它在 Windows 上运行没有错误,但之后 print() 不再刷新

最佳答案

可以确认 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

第一行立即出现在终端上,第二行在延迟一秒后出现。


然而,对于从 sys 导入 stdout 的代码,这将失败。幸运的是,没有多少代码可以做到这一点。

关于Python os.dup2 redirect 在 Windows python 控制台上启用输出缓冲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29167596/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com