Возможно, проблема вызвана несоответствием между ожидаемыми и фактическими типами данных внешней функции FUN
:
- Согласно правила неявной типизации данных в Fortran в
CALLBACK.F
, функция EXTERNAL
FUN
имеет неявный тип REAL
(поскольку нет явного типа или оператора IMPLICIT NONE
). - Однако, рассматривая подробности примера second в документации , где обертка F2PY создается явно с использованием
f2py -m callback2 -h callback2.pyf callback.f
, вы заметите, чторезультат r
внешней функции fun
определяется как имеющий тип real*8 :: r
(это также верно для неизмененного * * файла сигнатуры callback2.pyf
, так что это поведение по умолчанию F2PY).
Короче говоря, проблема в том, что FOO
ожидает, что FUN
вернет результат REAL
, в то время как со стороны оболочки Python и F2PY внешняя функция определена для возврата результата REAL*8
.Поэтому решение состоит в том, чтобы гарантировать, что FUN
имеет одинаковый тип возврата в Fortran и оболочке Python / F2PY.Это может быть достигнуто несколькими способами, например, путем добавления спецификации типа данных 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
Обтекание этого модифицированного CALLBACK.F
с python -m numpy.f2py -c -m callback callback.f
, как в примере, теперь даетжелаемый результат:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print(callback.foo(f))
110.0
Ради интереса, то же поведение, которое вы видели в Python / F2PY, может быть реализовано в чистом Fortran с использованием двух файлов prog.f
и fun.f
:
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
, оно выдает следующий результат (по сути тот же, что и ваш проблемный пример Python):
./a.out
BEFORE: 0.0000000000000000
AFTER: 0.0000000000000000
Раскомментирование обоих экземпляров REAL*8 FUN
в prog.f
и перекомпиляция решает проблему:
./a.out
BEFORE: 0.0000000000000000
AFTER: 110.00000000000000