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

时间:2021-09-01 00:05:51

I'm trying to figure out how to redirect output from some FORTRAN code for which I've generated a Python interface by using F2PY. I've tried:

我试图找出如何重定向一些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

This is the de facto method of redirecting output in Python, but it doesn't seem to work in this case (i.e., the output is displayed anyway).

这是在Python中重定向输出的事实上的方法,但在这种情况下似乎不起作用(即,无论如何都显示输出)。

I did find a mailing list post from 2002 saying that "It is possible to read messages from pts devices, e.g. ttysnoop does this". Information on ttysnoop seems to be pretty difficult to find online (I don't think it's been updated in quite a few years; for example, the first result on Google for "ttysnoop" has only dead links to tarballs, RPMs, and .deb's), and this request for a port to OS X received the response "No luck, it requires some linux specific utmp functions which I can't create."

我确实从2002年发现了一个邮件列表帖子,说“有可能从pts设备读取消息,例如ttysnoop这样做”。关于ttysnoop的信息似乎很难在网上找到(我不认为它已经在很多年内更新;例如,谷歌“ttysnoop”的第一个结果只有到tarball,RPM和.deb的死链接),这个对OS X端口的请求收到了响应“没有运气,它需要一些我无法创建的特定于Linux的特定功能。”

I'm open to any suggestions on how to redirect the output (it doesn't have to use ttysnoop).

我对如何重定向输出的任何建议持开放态度(它不必使用ttysnoop)。

Thanks!

2 个解决方案

#1


The stdin and stdout fds are being inherited by the C shared library.

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!"

#2


Here's a context manager that I recently wrote and found useful, because I was having a similar problem with distutils.ccompiler.CCompiler.has_function while working on pymssql. I also used the file descriptor approach but I used a context manager. Here's what I came up with:

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

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

The context for why I created this is at this blog post. Similar to yours I think.

我创建此文章的背景是在这篇博客文章中。我认为与你的相似。

I use it like this in a setup.py:

我在setup.py中使用它:

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

#1


The stdin and stdout fds are being inherited by the C shared library.

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!"

#2


Here's a context manager that I recently wrote and found useful, because I was having a similar problem with distutils.ccompiler.CCompiler.has_function while working on pymssql. I also used the file descriptor approach but I used a context manager. Here's what I came up with:

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

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

The context for why I created this is at this blog post. Similar to yours I think.

我创建此文章的背景是在这篇博客文章中。我认为与你的相似。

I use it like this in a setup.py:

我在setup.py中使用它:

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