1 回答
TA贡献1820条经验 获得超9个赞
您的示例的主要问题是ff.fortranFunc
只指定了它的返回类型,而不是它的参数类型。Fortran 子例程fortranFunc
有一个输入参数,type(c_funptr)
这也应该反映在 Python 端。
究竟如何实现解决方案,取决于您是否只想在 Python 中进行更改,或者也愿意在 Fortran 源代码中进行更改。我将概述这两种解决方案:
仅在 Python 中进行更改
以下是 Python 测试例程的更新版本(我称之为test.py
),具有以下特定更改:
指定
ff.fortranFunc.argtypes
the
arg_type
被指定为指向 a 的指针c_double
- 如何在 C 中传递标量参数回调函数
getSquareFromPython
也被修改以反映这一点x[0]
(有关最后两点的详细信息,请参阅ctypes 文档- 2.7 版本可能更清楚地解释了这一点)
import ctypes as ct
# callback function ctypes specification
return_type = ct.c_double
arg_type = ct.POINTER(ct.c_double)
func_spec = ct.CFUNCTYPE(return_type, arg_type)
# import dll and define result AND argument type
ff = ct.CDLL('FortranFunc_mod')
ff.fortranFunc.restype = None
ff.fortranFunc.argtypes = [ct.POINTER(func_spec),]
# decorate Python callback
@func_spec
def getSquareFromPython(x):
return x[0]**2
# call Fortran function
ff.fortranFunc( getSquareFromPython )
在 Python 和 Fortran 中进行更改
如果您希望更接近原始 Python 实现,也可以通过对以下内容进行以下更改来实现test.py:
changefortranFunc的参数类型:arg_type = ct.c_double
改变getSquareFromPython的返回值:x**2
但是,由于回调函数现在需要一个作为输入参数(而不是指向一个的指针),因此您必须通过将属性添加到虚拟参数c_double来更改 Fortran 抽象接口以反映这一点:valuex
abstract interface
function getSquare_proc( x ) result(xSquared) bind(C)
use, intrinsic :: iso_c_binding, only: c_double
real(c_double), intent(in), value :: x
real(c_double) :: xSquared
end function getSquare_proc
end interface
编译运行
编译并运行代码的任一修改版本,在 Windows 上使用 ifort 给我以下结果(适当更改编译命令和库名称,它也适用于 Linux 和 OS X 上的 gfortran):
> ifort /DLL FortranFunc_mod.f90 /o FortranFunc_mod.dll
...
> python test.py
xSquared = 4.00000000000000
注意两种情况的区别
getSquareFromPython通过查看' 参数的动态类型可以清楚地反映两种实现之间的差异x(它还解释了两种替代方案所需的符号更改)。对于提出的第一个替代方案,您可以将左侧的语句添加到getSquareFromPython,以获得右侧显示的结果:
print(type(x).__name__) : LP_c_double
print(type(x.contents).__name__) : c_double
print(type(x.contents.value).__name__) : float
print(type(x[0]).__name__) : float
print(x.contents.value == x[0]) : True
而对于第二种选择:
print(type(x).__name__) : float
添加回答
举报