You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含非C互操作派生类型的Fortran程序构建Python接口?

为非C互操作Fortran派生类型构建Python接口(Cython方案)

核心思路是用C互操作的不透明句柄封装原有非互操作类型,让Python/Cython只处理句柄,所有类型内部操作都在Fortran层完成,完全保留原有代码的模块化和多实例支持。

步骤1:Fortran层封装非互操作类型

不需要修改原有SomeType的定义和内部逻辑,只需要新增一套C互操作的接口子程序,通过句柄(指针包装)间接操作原有类型。

1.1 定义C互操作的句柄类型与封装接口

! 新增对外接口模块
module SomeType_C_Interface
  use iso_c_binding
  use SomeType_Module  ! 导入原有定义SomeType的模块
  implicit none

  ! C互操作的句柄,封装SomeType实例的指针
  type, bind(c) :: SomeType_Handle
    type(c_ptr) :: ptr = c_null_ptr  ! 存储SomeType实例的内存地址
  end type SomeType_Handle

contains

  ! 创建SomeType实例并返回句柄
  subroutine create_SomeType(handle) bind(c)
    type(SomeType_Handle), intent(out) :: handle
    type(SomeType), pointer :: instance

    allocate(instance)
    handle%ptr = c_loc(instance)  ! Fortran指针转C兼容指针
  end subroutine create_SomeType

  ! 封装原有init方法
  subroutine init_SomeType(handle) bind(c)
    type(SomeType_Handle), intent(inout) :: handle
    type(SomeType), pointer :: instance

    call c_f_pointer(handle%ptr, instance)  ! C指针转回Fortran指针
    call instance%init()  ! 调用原有类型绑定的初始化逻辑
  end subroutine init_SomeType

  ! 封装do_some_stuff方法
  subroutine do_some_stuff_SomeType(handle) bind(c)
    type(SomeType_Handle), intent(inout) :: handle
    type(SomeType), pointer :: instance

    call c_f_pointer(handle%ptr, instance)
    call instance%do_some_stuff()
  end subroutine do_some_stuff_SomeType

  ! 封装带参数的方法(参数需为C互操作类型)
  subroutine do_stuff_with_args_SomeType(handle, arg1, arg2) bind(c)
    type(SomeType_Handle), intent(inout) :: handle
    real(c_double), intent(in) :: arg1, arg2  ! 示例参数为C兼容的double
    type(SomeType), pointer :: instance

    call c_f_pointer(handle%ptr, instance)
    call instance%do_stuff_with_args(arg1, arg2)
  end subroutine do_stuff_with_args_SomeType

  ! 销毁实例释放内存
  subroutine finalize_SomeType(handle) bind(c)
    type(SomeType_Handle), intent(inout) :: handle
    type(SomeType), pointer :: instance

    if (c_associated(handle%ptr)) then
      call c_f_pointer(handle%ptr, instance)
      call instance%finalize()
      deallocate(instance)
      handle%ptr = c_null_ptr
    end if
  end subroutine finalize_SomeType

end module SomeType_C_Interface

步骤2:Cython层封装接口

通过Cython将Fortran的C互操作接口包装成Python类,让Python端调用流程与Fortran一致。

2.1 Cython代码(some_type.pyx)

cdef extern from "some_type_c_interface.h":
    # 对应Fortran的SomeType_Handle结构体
    ctypedef struct SomeType_Handle:
        void* ptr

    # 声明Fortran导出的C接口函数
    void create_SomeType(SomeType_Handle* handle)
    void init_SomeType(SomeType_Handle* handle)
    void do_some_stuff_SomeType(SomeType_Handle* handle)
    void do_stuff_with_args_SomeType(SomeType_Handle* handle, double arg1, double arg2)
    void finalize_SomeType(SomeType_Handle* handle)

cdef class SomeType:
    cdef SomeType_Handle handle

    def __cinit__(self):
        # 创建Fortran实例
        create_SomeType(&self.handle)

    def init(self):
        # 调用初始化方法
        init_SomeType(&self.handle)

    def do_some_stuff(self):
        do_some_stuff_SomeType(&self.handle)

    def do_stuff_with_args(self, arg1, arg2):
        # 传递C兼容参数
        do_stuff_with_args_SomeType(&self.handle, arg1, arg2)

    def __del__(self):
        # 自动销毁实例,避免内存泄漏
        finalize_SomeType(&self.handle)

步骤3:编译与使用

3.1 编译Fortran为共享库

以gfortran为例:

# 编译Fortran代码为目标文件
gfortran -c -fPIC some_type_module.f90 some_type_c_interface.f90 -o some_type.o
# 生成共享库
gfortran -shared some_type.o -o libsome_type.so

编译后会自动生成some_type_c_interface.h头文件(部分编译器需手动用gfortran -cpp -E预处理生成)。

3.2 编译Cython扩展

创建setup.py:

from setuptools import setup, Extension
from Cython.Build import cythonize

ext = Extension(
    name="some_type",
    sources=["some_type.pyx"],
    libraries=["some_type"],
    library_dirs=["."],
    include_dirs=["."]
)

setup(ext_modules=cythonize(ext))

执行编译:

python setup.py build_ext --inplace

3.3 Python端调用

from some_type import SomeType

# 调用流程与Fortran完全对齐
instance = SomeType()
instance.init()
instance.do_some_stuff()
instance.do_stuff_with_args(1.5, 3.0)
# 实例销毁时自动触发finalize,也可手动调用instance.__del__()

关键说明

  • 原有SomeType的非C互操作成员not_interoperable完全被隐藏在Fortran内部,Python无法访问,也不影响Fortran内部使用。
  • 每个PythonSomeType实例对应独立的FortranSomeType实例,支持多实例,无全局变量问题。
  • c_loc和c_f_pointer是Fortran与C指针转换的核心,确保跨语言内存地址传递正确。

内容的提问来源于stack exchange,提问作者tmph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:25:15