使用f2py停止(Fortran)模块错误中的Python代码?

8

我是一个有用的助手,可以翻译文本。

我正在使用 f2py 用 Fortran 创建一个 Python 模块。如果在 Fortran 模块中遇到错误,我想在 Python 程序中生成错误(包括错误消息)。请考虑以下示例:

Fortran 代码 (test.f):

subroutine foo(a,m)

  integer :: m,i
  integer, dimension(m) :: a
  !f2py intent(in) :: m
  !f2py intent(in,out) :: a
  !f2py intent(hide), depend(a) :: m=shape(a)

  do i = 1,m
    if ( a(i) .eq. 0 ) then
      print*, 'ERROR HERE..?'
    end if 
    a(i) = a(i)+1
  end do

end subroutine

这个非常简单的程序将a中的每个元素加上1。但是如果a(i)等于零,则应该产生错误。附带的Python代码:

import test

print test.foo(np.array([1,2],dtype='uint32'))
print test.foo(np.array([0,2],dtype='uint32'))

现在的输出为:
[2 3]
ERROR HERE..?
[1 3]

但我希望Python程序能够保留错误信息,请帮忙。

答案

Fortran中的stop命令正好可以做到这一点。考虑使用更新后的Fortran代码:

subroutine foo(a,m)

  integer :: m,i
  integer, dimension(m) :: a
  !f2py intent(in) :: m
  !f2py intent(in,out) :: a
  !f2py intent(hide), depend(a) :: m=shape(a)

  do i = 1,m
    if ( a(i) .eq. 0 ) then
      print*, 'Error from Fortran'
      stop
    end if 
    a(i) = a(i)+1
  end do

end subroutine

输出结果现在是:
[2 3]
Error from Fortran

即Python代码在错误发生后不会继续执行。

1
你是否试图从Fortran模块中引发Python异常? - user2357112
1
是的,这正是我想要做的。 - Tom de Geus
3
一种方法是从Fortran中返回一个错误代码,然后在Python端进行检查,如果发生错误,则引发异常。 - ev-br
3
Fortran不支持引发异常。 - Steve Lionel
1
这个numpy-dev邮件列表中的线程有一些解决您问题的方案:http://mail.scipy.org/pipermail/numpy-discussion/2009-January/039672.html - Robert T. McGibbon
显示剩余3条评论
2个回答

4

我建议numpy社区增加一个额外的f2py"增强"(raise_python_exception),这使得在Fortran中定义一个字符串变量成为可能,如果非空,则会导致Python在函数返回后引发异常。

因此,在Fortran中,您可以编写类似以下的代码:

subroutine calc_dq(q, temp, dq, error_mesg)
  !f2py raise_python_exception error_mesg

  real, intent(in) :: q, temp
  real, intent(out) :: dq

  character(len=100), intent(out) :: error_mesg

  if (.not. init_called()) then
     error_mesg = "`init` hasn't been called."
  else
     call q_flux_function(q, temp, dq)
  endif
end subroutine calc_dq

通过Python调用时,error_mesg变量的内容将被用作异常的内容:

In [2]: calc_dq(1.0, 300.)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-8-c0ce0cb9cda1> in <module>()
----> 1 calc_dq(1.0, 300.)

Exception: `init` hasn't been called.

我认为这是从Fortran中引发异常的一种非常方便的方法,因为它允许轻松定义异常信息。我已经将我的建议发布在Github上


在您的示例中,另一个条件分支中error_mesg的值未定义。 - Vladimir F Героям слава

1
确实提供了一些可以用来引发异常的语句。详见这里
特别是要看一下callstatement,它描述了如何添加f2py_success = 0以触发异常。
我不确定这是否能帮助您调试Fortran库的内部问题,但至少这是一个开始。

现在的链接:https://numpy.org/doc/stable/f2py/signature-file.html#statements,以及从Wayback Machine恢复的链接:https://web.archive.org/web/20140625200426/http://cens.ioc.ee/projects/f2py2e/usersguide/#statements - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接