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

时间:2009-06-10 19:59:16

标签: python unix fortran stdout

我正在试图弄清楚如何使用F2PY从我为其生成Python接口的一些FORTRAN代码重定向输出。我试过了:

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的死链接)和{ {3}}收到回复“没有运气,它需要一些我无法创建的linux特定的utmp函数。”

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

谢谢!

2 个答案:

答案 0 :(得分:18)

stdin和stdout 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!"

答案 1 :(得分:4)

这是我最近编写的context manager并发现有用,因为我在处理distutils.ccompiler.CCompiler.has_function时遇到与pymssql类似的问题。我也使用了文件描述符方法,但我使用了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')