【问题标题】:Redirecting FORTRAN (called via F2PY) output in Python在 Python 中重定向 FORTRAN(通过 F2PY 调用)输出
【发布时间】:2009-06-10 19:59:15
【问题描述】:

我试图弄清楚如何重定向一些 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 中重定向输出的事实上的方法,但在这种情况下它似乎不起作用(即,输出仍然显示)。

我确实发现 a mailing list post from 2002 说“可以从 pts 设备读取消息,例如 ttysnoop 会这样做”。关于 ttysnoop 的信息似乎很难在网上找到(我认为它已经有好几年没有更新了;例如,the first result on Google for "ttysnoop" 只包含指向 tarball、RPM 和 .deb 的死链接)和this request for a port to OS X收到响应“不走运,它需要一些我无法创建的特定于 linux 的 utmp 函数。”

我愿意接受有关如何重定向输出的任何建议(不必使用 ttysnoop)。

谢谢!

【问题讨论】:

  • 您确定 fortran 输出不会进入 stderr 而不是 stdout?
  • 是的,我也尝试过重定向它,得到了相同的结果。

标签: python unix fortran stdout


【解决方案1】:

标准输入和标准输出 fds 被 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!"

【讨论】:

  • 这也会抑制标准错误吗?如果没有,如何实现?
  • @aberration:不知道,你有没有用任何写入 stderr 的 fortran 程序测试它?
  • 我试过了,它似乎确实显示了写入 stderr 的文本。
  • 感谢这个非常有用的答案。当我将此代码添加到需要多次重定向输出作为循环的一部分的脚本中时,我注意到我正在泄漏文件描述符。我相信你最后还需要os.close(save[0])os.close(save[1])来防止泄漏。
  • @SibbsGambling 文件描述符
【解决方案2】:

这是我最近编写并发现有用的context manager,因为我在处理pymssql 时遇到了与distutils.ccompiler.CCompiler.has_function 类似的问题。我也使用了文件描述符方法,但我使用了context manager。这是我想出的:

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()

我创建它的原因是this blog post。我觉得和你的差不多。

我在setup.py 中这样使用它:

with stdchannel_redirected(sys.stderr, os.devnull):
    if compiler.has_function('clock_gettime', libraries=['rt']):
        libraries.append('rt')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多