在Python中重定向FORTRAN(通过F2PY调用)输出
我正在尝试将一些FORTRAN代码的输出重定向到我用F2PY生成的Python接口中。我试过了:
from fortran_code import fortran_function
stdout_holder = sys.stdout
stderr_holder = sys.stderr
sys.stdout = file("/dev/null","w")
fortran_function()
sys.stdout.close()
sys.stderr.close()
sys.stdout = stdout_holder
sys.stderr = stderr_holder
这在Python中是重定向输出的常用方法,但在这种情况下似乎不管用(也就是说,输出还是会显示出来)。
我找到了一篇2002年的邮件列表帖子,里面提到“可以从pts设备读取消息,比如ttysnoop就是这么做的”。不过,关于ttysnoop的信息在网上似乎很难找到(我觉得它已经好几年没有更新了;例如,在Google上搜索“ttysnoop”得到的第一个结果只有一些死链接,指向压缩包、RPM和.deb文件),而且关于移植到OS X的请求得到了“没有成功,它需要一些特定于Linux的utmp函数,我无法创建”的回复。
我对任何重定向输出的建议都持开放态度(不一定要使用ttysnoop)。
谢谢!
2 个回答
8
这是我最近写的一个上下文管理器,我觉得它很有用,因为我在处理distutils.ccompiler.CCompiler.has_function
时遇到了类似的问题,那个时候我在做pymssql的工作。我也尝试过文件描述符的方法,但我选择使用了上下文管理器。这是我想到的解决方案:
import contextlib
@contextlib.contextmanager
def stdchannel_redirected(stdchannel, dest_filename):
"""
A context manager to temporarily redirect stdout or stderr
e.g.:
with stdchannel_redirected(sys.stderr, os.devnull):
if compiler.has_function('clock_gettime', libraries=['rt']):
libraries.append('rt')
"""
try:
oldstdchannel = os.dup(stdchannel.fileno())
dest_file = open(dest_filename, 'w')
os.dup2(dest_file.fileno(), stdchannel.fileno())
yield
finally:
if oldstdchannel is not None:
os.dup2(oldstdchannel, stdchannel.fileno())
if dest_file is not None:
dest_file.close()
我创建这个的背景可以在这篇博客中找到。我觉得和你的情况类似。
在我的setup.py
中,我是这样使用它的:
with stdchannel_redirected(sys.stderr, os.devnull):
if compiler.has_function('clock_gettime', libraries=['rt']):
libraries.append('rt')
25
标准输入和标准输出的文件描述符正在被C语言的共享库继承。
from fortran_code import fortran_function
import os
print "will run fortran function!"
# open 2 fds
null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
# save the current file descriptors to a tuple
save = os.dup(1), os.dup(2)
# put /dev/null fds on 1 and 2
os.dup2(null_fds[0], 1)
os.dup2(null_fds[1], 2)
# *** run the function ***
fortran_function()
# restore file descriptors so I can print the results
os.dup2(save[0], 1)
os.dup2(save[1], 2)
# close the temporary fds
os.close(null_fds[0])
os.close(null_fds[1])
print "done!"