当我调用以下函数时,它将按预期返回1
:
integer function my_func() result(myresult)
myresult = 1
end function my_func
但是当我修改返回值的名称以字母“ r”开头时,该函数将返回0
。
integer function my_func() result(rresult)
rresult = 1
end function my_func
是什么原因造成的?我首先想到的是它与隐式键入有关,但是该函数位于指定implicit none
的模块中。
这是完整的模块
module my_mod
implicit none
contains
integer function my_func() result(myresult)
myresult = 1
end function my_func
end module my_mod
我正在使用Fortran 90并使用gfortran进行编译。
编辑
这是一个演示问题的完整程序
Makefile:
.PHONY: pytest clean
CYTHON_LIB = fortran_mods.cpython-37m-x86_64-linux-gnu.so
FFLAGS += -fdefault-real-8
pytest: $(CYTHON_LIB)
./tests.py
$(CYTHON_LIB): my_mod.F90
f2py -c -m fortran_mods my_mod.F90 --f90flags="$(FFLAGS)"
clean:
rm *.so
my_mod.F90:
module my_mod
implicit none
contains
!********************************************************
integer function my_func_without_r() result(myresult)
myresult = 1
end function
integer function my_func_with_r() result(rresult)
rresult = 1
end function
end module my_mod
tests.py
#!/usr/bin/env python3
import fortran_mods
from fortran_mods import *
print("with r:", my_mod.my_func_with_r())
print("without r:", my_mod.my_func_without_r())
运行make pytest
并且在Makefile中包含FFLAGS += -fdefault-real-8
时的输出是
with r: 0.0
without r: 1
否则为
with r: 1.0
without r: 1
答案 0 :(得分:4)
这里的问题肯定是F2PY如何包装Fortran函数,而不是Fortran代码本身。
要对F2PY如何包装函数有更多的了解(尤其是如果事情无法按预期进行),它总是有助于将过程分成多个部分(请参见The smart way)。因此,首先创建一个签名文件,让您了解F2PY如何解释您的代码。对于您的特定示例,运行:
f2py -m fortran_mods -h my_mod.pyf my_mod.F90
这将产生一个签名文件my_mod.pyf
,看起来像这样:
python module fortran_mods ! in
interface ! in :fortran_mods
module my_mod ! in :fortran_mods:my_mod.F90
function my_func_without_r() result (myresult) ! in :fortran_mods:my_mod.F90:my_mod
integer :: myresult
end function my_func_without_r
function my_func_with_r() result (rresult) ! in :fortran_mods:my_mod.F90:my_mod
real :: rresult
end function my_func_with_r
end module my_mod
end interface
end python module fortran_mods
很明显,F2PY将my_func_with_r
的结果变量rresult
误识别为real
。您可以简单地将{{1}中的real :: rresult
替换为integer :: rresult
中的my_mod.pyf
,进行F2PY包装的下一步/第二步,并使用更正的签名文件进行编译:
f2py -c my_mod.pyf my_mod.F90
您的python脚本现在应该提供预期的输出。
如果要包装的功能很多,可能不需要这种修改签名文件的方法。 F2PY可能造成困难的原因是您的函数定义使用结果变量,而函数的类型定义中没有出现它们的类型定义(即F2PY问题,而不是Fortran问题)。如果您将函数定义更改为例如:
function my_func_with_r() result(rresult)
integer :: rresult
rresult = 1
end function
或
integer function my_func_with_r()
my_func_with_r = 1
end function
您可以像最初一样一步完成F2PY包装,并且仍然应该获得正确的输出。
最后,我将对评论中提出的问题再投一票:在将函数与F2PY封装在一起会引起麻烦时,请使用-fdefault-real-8
。对于make a Fortran procedure callable from Python,F2PY创建:
Python C / API扩展模块(称为包装器模块),该模块 实现Python扩展功能(用C编写,称为 包装函数),依次调用给定的Fortran过程。
整个过程基于F2PY如何解释Fortran源代码中的数据类型-如果源代码是使用更改声明的数据类型的编译器标志编译的,则事情肯定会坏掉(直接类似于{{1 }} / real
与您最初的问题不匹配)。因此,应该在Fortran代码本身中显式设置变量和函数的数据类型,有关Fortran的integer
参数,请参见here和here,以及与{尤其是F2PY。