我想了解F2PY是如何工作的。要做到这一点,我写了一个简单的Fortran函数,它接受一个数组作为输入并返回该数组的元素的总和。
我写了三个不同版本的相同的功能,这是我希望保持相同的结果:
function rsum(arr)
real, dimension(:), intent(in) :: arr
real :: rsum
rsum=sum(arr)
end function rsum
function rsum1(arr)
real(8), dimension(:), intent(in) :: arr
real(8) :: rsum1
rsum1=sum(arr)
end function rsum1
function rsum2(arr) result(s)
real, dimension(:), intent(in) :: arr
real :: s
s=sum(arr)
end function rsum2
function rsum3(arr) result(s)
real(8), dimension(:), intent(in) :: arr
real(8) :: s
s=sum(arr)
end function rsum3
我的python脚本来测试这些功能如下:
from numpy import *
import ftest as f
a=array(range(3))
print(f.rsum(a))
print(f.rsum1(a))
print(f.rsum2(a))
print(f.rsum3(a))
但结果是这样的:
3.0
0.0
3.0
3.0
所有的结果是正确的,除了rsum1
的一个,这是0.0
。我觉得更奇怪的是,rsum3
,其中我只是改变功能(或者,至少,我想我这样做)的结果的名字,完美的作品!
我知道这事做Fortran和numpy的之间的类型转换,但我不明白的问题是什么。
PS:我只学过的Fortran最近。
该问题的根本原因是与使用的假定形状伪参数(即arr
)在功能。 Fortran语言需要这样的功能有明确的接口。 @VladimirF给了一个很好的答案,关于这一点你(有关?)问题here,表明首选的方案是把功能模块中。假设你的代码函数列表保存在一个名为funcs.f90
,你可以简单地把它们放入一个模块,例如所谓mod_funcs.f90
,就像这样:
module mod_funcs
implicit none
contains
include "funcs.f90"
end module mod_funcs
与F2PY python -m numpy.f2py -m ftest -c mod_funcs.f90
这个包裹,更新你的Python测试脚本import语句from ftest import mod_funcs as f
,然后运行它,以获得预期的结果:
3.0
3.0
3.0
3.0
Fortran语言function
s由F2PY包裹在subroutine
s。为了支持假定形状阵列在Fortran符合标准的方式,创建F2PY子程序包装包含interface
s用于与假定形状伪参数的用户定义的函数。您可以通过使用F2PY包裹时指定一个build目录用--build-dir
标志,例如看看这些包装像这样:
python -m numpy.f2py --build-dir .\build -m ftest -c funcs.f90
看着这对有问题的功能rsum1
被泄露(我是从ftest-f2pywrappers.f
逐字抄袭保持F2PY的缩进)创建的包装:
subroutine f2pywraprsum1 (rsum1f2pywrap, arr, f2py_arr_d0)
integer f2py_arr_d0
real(8) arr(f2py_arr_d0)
real(8) rsum1f2pywrap
interface
function rsum1(arr)
real(8), dimension(:),intent(in) :: arr
end function rsum1
end interface
rsum1f2pywrap = rsum1(arr)
end
需要注意的是,由于implicit data typing rules,为interface
的rsum1
意味着函数real
数据类型,无法按照预期的real(8)
- 所以在接口数据类型不匹配!这就解释了为什么有一个明确的result
声明(rsum3
)看似相同的功能,在你原来的例子返回正确的结果,其结果具有正确的数据类型。通过在命名你的职责造化,rsum
有正确的接口。如果更改rsum
的名字例如isum
在其F2PY子程序封装接口隐式数据类型规则将意味着它有一个integer
结果,你会从你的(修改以反映名称的更改从fsum
到isum
)python脚本输出如下:
0.0
0.0
3.0
3.0
所以对我来说看起来好像有可能在F2PY如何创建一个用于虚拟形状的哑参数的函数接口(可以直接把这些功能集成到一个模块可以绕过一个bug,或者通过使用功能result
的明确声明返回值)。
为了完整起见,我用Python 3.6.3 :: Intel Corporation
,与NumPy 1.14.3
和GNU Fortran (GCC) 8.2.0
。