2009-06-10 103 views
11

我想弄清楚如何使用F2PY爲其生成Python接口的某些FORTRAN代碼重定向輸出。我已經試過:在Python中重定向FORTRAN(通過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重定向輸出的實際方法,但它似乎並不在此情況下(即,無論如何顯示輸出)工作。

我確實發現a mailing list post from 2002表示「有可能從pts設備讀取消息,例如ttysnoop會這樣做」。有關ttysnoop的信息似乎很難在網上找到(我認爲它不會在幾年內更新;例如,the first result on Google for "ttysnoop"與tarballs,RPM和.deb只有死鏈接),並且this request for a port to OS X收到響應「沒有運氣,它需要一些我無法創建的特定於linux的utmp功能。「

我接受任何關於如何重定向輸出的建議(它不必使用ttysnoop)。

謝謝!

+1

你確定FORTRAN輸出不會標準錯誤而不是標準輸出? – 2009-06-10 20:36:30

+0

是的,我只是嘗試重定向它,並得到了相同的結果。 – srunni 2009-06-10 20:55:04

回答

17

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