当我更改结果变量的名称时,为什么用f2py编译的Fortran函数返回零?

Pau*_*ntz 2 fortran f2py

当我调用以下函数时,它会1按预期返回:

integer function my_func() result(myresult)
    myresult = 1
end function my_func
Run Code Online (Sandbox Code Playgroud)

但是,当我将返回值的名称修改为以字母“ r”开头时,该函数将返回0

integer function my_func() result(rresult)
    rresult = 1
end function my_func
Run Code Online (Sandbox Code Playgroud)

是什么原因造成的?我的第一个想法是,它与隐式类型有关,但该函数位于指定的模块中implicit none

这是完整的模块

module my_mod
implicit none

contains

integer function my_func() result(myresult)
    myresult = 1
end function my_func

end module my_mod
Run Code Online (Sandbox Code Playgroud)

我正在使用Fortran 90并使用gfortran进行编译。

编辑

这是演示该问题的完整程序

生成文件:

.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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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())
Run Code Online (Sandbox Code Playgroud)

当输出make pytest运行,并FFLAGS += -fdefault-real-8包含在Makefile中是

with r: 0.0
without r: 1
Run Code Online (Sandbox Code Playgroud)

否则是

with r: 1.0
without r: 1
Run Code Online (Sandbox Code Playgroud)

jbd*_*bdv 5

这里的问题肯定是F2PY如何包装Fortran函数,而不是Fortran代码本身。

为了对F2PY如何包装函数有更多的了解(尤其是如果事情无法按预期进行),它总是有助于将流程分成多个部分(请参阅智能方法)。因此,首先创建一个签名文件,使您可以查看F2PY如何解释您的代码。对于您的特定示例,运行:

f2py -m fortran_mods -h my_mod.pyf my_mod.F90
Run Code Online (Sandbox Code Playgroud)

这将生成一个如下所示的签名文件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
Run Code Online (Sandbox Code Playgroud)

显然,F2PY将错误my_func_with_r的结果变量标识rresultreal。你可以简单地更换real :: rresult与预期integer :: rresultmy_mod.pyf,采取F2PY包装的下一/第二个步骤,并使用校正签名文件编译:

f2py -c my_mod.pyf my_mod.F90
Run Code Online (Sandbox Code Playgroud)

您的python脚本现在应该提供预期的输出。

如果您有很多要包装的功能,则可能不需要这种修改签名文件的方法。F2PY可能造成困难的是,您的函数定义使用结果变量,而函数的类型定义中没有出现它们的类型定义(即,F2PY问题,而不是Fortran问题)。如果将函数定义更改为例如:

function my_func_with_r() result(rresult)
    integer :: rresult
    rresult = 1
end function
Run Code Online (Sandbox Code Playgroud)

要么

integer function my_func_with_r()
    my_func_with_r = 1
end function
Run Code Online (Sandbox Code Playgroud)

您可以像原始操作一样一步完成F2PY包装,并且仍应获得正确的输出。

最后,我将对评论中提出的问题再投一票:-fdefault-real-8在将函数与F2PY一起包装时使用会带来麻烦。为了使Fortran过程可从Python调用,F2PY创建:

一个Python C / API扩展模块(称为包装器模块),该模块实现一个Python扩展功能(用C编写,称为包装器功能),该功能又调用给定的Fortran过程。

整个过程基于F2PY如何解释Fortran源代码中的数据类型-如果源代码是使用更改声明的数据类型的编译器标志进行编译的,那么事情肯定会坏掉(直接类似于real/ integer原始问题是/ 不匹配)关于)。为您的变量和函数的数据类型,因此应该在Fortran代码本身进行明确设置,见这里这里的Fortran的kind参数一般,而在这里特别是有关F2PY。

  • 我已经编辑了答案,以解释使用`-fdefault-real-8`的危险,并添加了指向其他问题/答案的链接,以解释如何在Fortran代码中正确定义浮点精度。 (2认同)