在Python中重定向FORTRAN(通过F2PY调用)输出

14 投票
2 回答
14416 浏览
提问于 2025-04-15 12:10

我正在尝试将一些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!"

撰写回答