Перенаправление вывода FORTRAN (вызывается через F2PY) в Python
Я пытаюсь выяснить, как перенаправить вывод из некоторого кода FORTRAN, для которого я сгенерировал интерфейс Python, используя F2PY. Я пробовал:
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" содержит только мертвые ссылки на tarballs, RPM и.deb's), и на этот запрос о порте для OS X был получен ответ: "Не повезло, для этого требуются некоторые специфичные для Linux функции utmp, которые я не могу создать".
Я открыт для любых предложений о том, как перенаправить вывод (он не должен использовать ttysnoop).
Спасибо!
2 ответа
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!"
Вот менеджер контекста, который я недавно написал и нашел полезным, потому что у меня была похожая проблема с 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')