Python 3:无缓冲流和缓冲流

时间:2015-01-26 23:46:02

标签: python python-3.x

我一直在使用以下代码段来沉默(重定向输出)我的Python脚本中调用的C代码:

from ctypes import CDLL, c_void_p
import os
import sys

# Code
class silence(object):
    def __init__(self, stdout=os.devnull):
        self.outfile = stdout

    def __enter__(self):
        # Flush
        sys.__stdout__.flush()

        # Save
        self.saved_stream = sys.stdout
        self.fd = sys.stdout.fileno()
        self.saved_fd = os.dup(self.fd)

        # Open the redirect
        self.new_stream = open(self.outfile, 'wb', 0)

        self.new_fd = self.new_stream.fileno()

        # Replace
        os.dup2(self.new_fd, self.fd)

    def __exit__(self, *args):
        # Flush
        self.saved_stream.flush()

        # Restore
        os.dup2(self.saved_fd, self.fd)
        sys.stdout = self.saved_stream

        # Clean up
        self.new_stream.close()
        os.close(self.saved_fd)


# Test case
libc = CDLL('libc.so.6')


# Silence!
with silence():
    libc.printf(b'Hello from C in silence\n')

我们的想法是重定向与stdout关联的fd,并将其替换为与打开的空设备关联的fd。不幸的是,它在Python 3下无法正常工作:

$ python2.7 test.py
$ python3.3 -u test.py
$ python3.3 test.py
Hello from C in silence

在具有无缓冲输出的Python 2.7和3.3下, 工作。但是,我不确定其根本原因是什么。即使stdout被缓冲,对sys.saved_stream.flush()的调用最终也应该在C级调用fflush(stdout)(将输出刷新到空设备)。

我误解了Python 3 I / O模型的哪个部分?

2 个答案:

答案 0 :(得分:1)

我不是100%确定我理解Py3 I / O模型,而是添加

    sys.stdout = os.fdopen(self.fd, 'wb', 0)

在你被赋予self.fd后,在Python 3.4中为我修复了它(在我添加这个语句之前,我能够在3.4中重现这个问题)。

答案 1 :(得分:0)

我不完全确定会发生什么,但在我的系统上有两种解决方法:

  • self.saved_stream.flush()中的__exit__来电替换为libc.fflush(None)
  • 在调用libc.printf之前使用任意字符串调用silence(),例如:

    libc = CDLL('/bin/cygwin1.dll')
    libc.printf(b'')
    

此外,只有第二种方式,Python printlibc.printf的输出在with silence():阻止后仍保持同步。