我有以下关于f2py和回调函数的examples shown in the numpy docs的一个麻烦。我所执行的确切相同的步骤,在第一个例子(即f2py -c -m callback callback.f
)来包装callback.f
:
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
然而,测试结果作为例子,给我:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print callback.foo(f)
0.0
因此,返回的0.0
代替110.0
,其中0.0
是r
在Fortran代码的初始值。不管我用哪个回调函数,结果仍然相同(不变R
)。我使用的是从python 3.7
获得numpy
和conda
的最新版本。
你可以重现这个问题,还是我做错了什么?
这个问题似乎由预期的和实际的数据类型的外部函数FUN
之间的失配引起的:
CALLBACK.F
(因为没有明确的类型,或EXTERNAL
语句)。FUN
,其中F2PY包装是明确创建使用REAL
的细节,你会注意到,外部函数IMPLICIT NONE
的结果second example in the documentation被定义为具有类型f2py -m callback2 -h callback2.pyf callback.f
(这也适用于未修改r
签名文件,所以这是默认F2PY行为)。总之问题是,fun
预计real*8 :: r
返回一个callback2.pyf
结果,当从Python和F2PY包装纸侧的外部函数定义返回一个FOO
结果。因此,一个解决方案是确保FUN
在Fortran和Python的/ F2PY包装相同的返回类型。这可以以几种方式通过添加REAL
一个数据类型说明REAL*8
来实现,例如:
FUN
包装用REAL*8 FUN
如示例中该修改CALLBACK.F
,现在得到所需的输出:
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
对于利益起见,可以在纯Fortran语言使用两个文件CALLBACK.F
和python -m numpy.f2py -c -m callback callback.f
生产,你在Python / F2PY看到相同的行为:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print(callback.foo(f))
110.0
和
prog.f
使用fun.f
编译,它提供了以下输出(实际上与您的问题的Python的例子):
C FILE: PROG.F, including subroutine FOO previously in CALLBACK.F
PROGRAM MAIN
C REAL*8 FUN
EXTERNAL FUN
REAL*8 R
R = 0
PRINT *, "BEFORE: ", R
CALL FOO(FUN, R)
PRINT *, "AFTER: ", R
END
C This is copied from CALLBACK.F
SUBROUTINE FOO(FUN,R)
C REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
在取消在C FILE: FUN.F containing the function to be called by FOO
REAL*8 FUNCTION FUN(I)
INTEGER I
FUN = I*I
END
和重新编译gfortran -fcheck=all -Wall -g func.f prog.f
的两个实例解决了这个问题:
./a.out
BEFORE: 0.0000000000000000
AFTER: 0.0000000000000000