【发布时间】:2015-01-26 23:46:01
【问题描述】:
我一直在使用以下 sn-p 来使我的 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 模型的哪一部分?
【问题讨论】:
-
如果对标准输出的写入来自 C 库代码(例如 printf 和朋友),redirect_stdout 没有帮助。
-
阅读完整答案(注意函数名)
-
抱歉错字,我的评论是关于答案中提供的 stdout_redirected 函数。当 C 库 stdio 函数与他们自己的缓冲品牌混合时,它不会处理这种情况(因此会遇到与上述 sn-p 相同的问题)。
-
是的,这可能是因为 Python 3 I/O(与 Python 2 不同)不使用 stdio 处理标准流,因此调用
stdout.flush()可能还不够。如果您按照@Kolmar 的建议添加相应的libc.fflush(None)调用,是否有帮助?如果您只对 stdio 流感兴趣,那么您可以使用freopen()函数来重定向标准 stdio 流。
标签: python python-3.x