2015-01-26 138 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():塊同步的輸出。