如何从Fortran调用Python函数?含TensorFlow与数组传递需求
从Fortran调用Python函数并传递数组到TensorFlow的可行方案
方案一:利用f2py实现反向调用(Fortran调Python)
f2py支持反向调用,可直接通过它生成的接口让Fortran调用Python函数,步骤如下:
编写Fortran驱动代码
声明要调用的Python函数接口,直接传递Fortran数组:program call_python_tf implicit none real, dimension(2,3) :: fortran_arr integer :: i, j ! 初始化列优先的Fortran数组 do j=1,3 do i=1,2 fortran_arr(i,j) = real(i+j) end do end do ! 调用Python端的TensorFlow处理函数 call py_tf_processor(fortran_arr) end program call_python_tf编写Python回调函数
用f2py.callback装饰器定义被Fortran调用的函数,自动处理数组转换并对接TensorFlow:import numpy as np import tensorflow as tf import f2py @f2py.callback def py_tf_processor(arr): # f2py自动将Fortran数组转为numpy数组(保留列优先布局) np_arr = np.asarray(arr) # 转换为TensorFlow张量并执行运算 tf_tensor = tf.convert_to_tensor(np_arr, dtype=tf.float32) result = tf.matmul(tf_tensor, tf_tensor, transpose_b=True) print("TensorFlow运算结果:\n", result.numpy()) return编译绑定并运行
用f2py编译生成可调用模块:f2py -c -m fortran_py_bridge fortran_code.f90 python_callback.py直接运行生成的模块,或在Fortran环境中调用即可。
方案二:通过ISO_C_BINDING借助C语言中转
如果f2py的方式无法满足定制需求,C作为中间层是更灵活的选择:
编写C中转函数
嵌入Python解释器调用逻辑,处理Fortran数组的C绑定:#include <Python.h> #include <numpy/arrayobject.h> // Fortran可调用的C函数(注意Fortran会自动给函数名加下划线) void call_python_tf_(float *arr, int *rows, int *cols) { // 初始化Python解释器(长期运行的程序建议只初始化一次) if (!Py_IsInitialized()) { Py_Initialize(); import_array(); // 初始化numpy C API } // 导入Python端的TensorFlow处理模块 PyObject *pModule = PyImport_ImportModule("tf_handler"); PyObject *pFunc = PyObject_GetAttrString(pModule, "process_array"); // 将C数组转为numpy数组(复用Fortran内存,无拷贝) npy_intp dims[2] = {*rows, *cols}; PyObject *pArr = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, arr); // 调用Python函数并传递数组 PyObject *pArgs = PyTuple_New(1); PyTuple_SetItem(pArgs, 0, pArr); PyObject_CallObject(pFunc, pArgs); // 清理资源(长期运行的程序可延迟清理) Py_DECREF(pArgs); Py_DECREF(pArr); Py_DECREF(pFunc); Py_DECREF(pModule); }编写Fortran绑定代码
用iso_c_binding声明C函数接口,传递数组参数:program call_via_c use iso_c_binding implicit none interface subroutine call_python_tf(arr, rows, cols) bind(C, name='call_python_tf_') import :: c_float, c_int real(c_float), intent(inout) :: arr(*) integer(c_int), intent(in) :: rows, cols end subroutine call_python_tf end interface real(c_float), dimension(2,3) :: fortran_arr integer(c_int) :: rows=2, cols=3 integer :: i,j ! 初始化数组 do j=1,3 do i=1,2 fortran_arr(i,j) = real(i+j, c_float) end do end do ! 通过C中转调用Python函数 call call_python_tf(fortran_arr, rows, cols) end program call_via_c编写Python TensorFlow处理脚本(tf_handler.py)
import tensorflow as tf import numpy as np def process_array(arr): tf_tensor = tf.convert_to_tensor(arr, dtype=tf.float32) print("输入Fortran数组:\n", arr) result = tf.reduce_mean(tf_tensor) print("TensorFlow均值计算结果:", result.numpy()) return编译运行
- 编译C代码为共享库:
gcc -shared -fPIC -I/usr/include/python3.x -lpython3.x -lnumpy c_bridge.c -o libpybridge.so - 编译Fortran代码:
gfortran fortran_caller.f90 libpybridge.so -o fortran_c_py - 运行程序:
./fortran_c_py
- 编译C代码为共享库:
关键注意事项
- 内存效率:两种方案都支持直接复用Fortran数组内存,无需额外拷贝,适合处理大数组。
- 解释器生命周期:如果Fortran程序长期运行,避免频繁初始化/销毁Python解释器,可在程序启动时初始化一次。
- 架构一致性:确保Python、Fortran、C的编译架构(32/64位)完全一致,避免兼容性问题。
内容的提问来源于stack exchange,提问作者Nicola Clinco
相关产品推荐
相关产品推荐

