2015-01-26 91 views
4

我一直在使用下面的代码片断沉默(重定向从输出)叫我的Python脚本的C代码:的Python 3:无缓冲VS缓冲流

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将其替换为与打开的空设备关联的一个。与无缓冲输出

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

下的Python 2.7和3.3这确实工作:不幸的是,它没有的Python 3下正常工作。不过,我不确定其根本原因。即使stdout被缓冲,对sys.saved_stream.flush()的调用最终应在C级调用fflush(stdout)(将输出清空到空设备)。

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

+0

尝试['与stdout_redirected():'](http://stackoverflow.com/a/22434262/4279) – jfs 2015-01-27 08:31:50

+0

redirect_stdout没有帮助,如果写入标准输出来自C库代码(如printf和朋友)。 – 2015-01-27 11:35:38

+0

阅读完整答案(注意函数名称) – jfs 2015-01-27 11:37:03

回答

1

我不是100%肯定我明白PY3 I/O模型下去,但你分配self.fd修复它为我在Python 3.4之后加入

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

(我是能够重现在我添加此语句之前,在3.4中有问题)。

0

我不完全知道是什么或者怎么回事,但我的系统上有两种方法来解决这个问题:

  • libc.fflush(None)更换呼叫self.saved_stream.flush()__exit__
  • 呼叫libc.printf与任何字符串主叫silence(),例如之前:

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

另外,仅与第二种方式具有Python的printlibc.printf保持后with silence():块同步的输出。