我一直在使用以下代码片段来静音(重定向从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)(将输出刷新到null设备)。我是否误解了Python 3 I/O模型的哪个部分?
with stdout_redirected():
(https://dev59.com/7m445IYBdhLWcg3w1tgS#22434262) - jfsstdout.flush()
可能不足够。如果您按照@Kolmar的建议添加相应的libc.fflush(None)
调用,是否有所帮助?如果您只对stdio流感兴趣,则可以使用freopen()
函数重定向标准stdio流。 - jfsfflush(None)
是一个合理的解决方案,如果我能够找到一种可移植的方式从ctypes获取libc的句柄。 - Freddie Witherden