f2py封装Fortran子程序时可选参数被自动赋值引发错误求助
问题:f2py调用Fortran可选字符参数时触发错误
我用f2py封装Fortran模块module.f90,在Python中调用时遇到异常:子程序checkpoint的可选字符参数mode未传入时,被识别为随机值,触发错误分支。
Fortran模块代码
module checkpt implicit none contains subroutine checkpoint(cpt, debug, mode, file_name) implicit none integer, intent(in) :: cpt logical, intent(in) :: debug character(len=*), optional :: mode character(len=*), intent(in), optional :: file_name character(len=30) :: def_name = 'checkpoint.dat' if(present(file_name)) def_name = file_name ! -- some code... ! check if a mode is selected and print the correct stuff if(present(mode)) then if(mode .eq. 'TIME') then ! -- do some stuff... else if(mode .eq. 'VALUES') then ! -- do other stuff... else stop "ERROR - Wrong checkpoint mode: must be one among 'VALUES','TIME'." end if end if end subroutine checkpoint end module checkpt
Python调用代码
from fmatmult import f_mat_mult as fmm from fcheckpt import checkpt as cpt debug = True sizes = [50,100,200,400,800]#,1600,3200,6400] for i in range(len(sizes)): fmm.mat_mult1(sizes[i]) cpt.checkpoint(cpt=1,debug=debug)
报错信息
STOP ERROR - Wrong checkpoint mode: must be one among 'VALUES','TIME'.
原因分析
f2py对未指定intent(in)的字符型可选参数处理存在缺陷,无法正确识别present()的状态——即使Python未传入参数,present(mode)仍会返回.true.,此时读取到的是内存中的随机字符,触发错误分支。
解决方法
1. 补全可选参数的intent声明
给mode参数补上intent(in),让f2py能正确识别可选参数的传入状态:
subroutine checkpoint(cpt, debug, mode, file_name) implicit none integer, intent(in) :: cpt logical, intent(in) :: debug character(len=*), intent(in), optional :: mode ! 新增intent(in) character(len=*), intent(in), optional :: file_name character(len=30) :: def_name = 'checkpoint.dat' ! ... 其余代码不变 end subroutine checkpoint
2. 重新编译模块
用f2py重新编译修改后的Fortran代码,确保生成新的Python接口:
f2py -c -m fcheckpt module.f90
3. Python调用时显式跳过可选参数(可选)
如果修改后仍有问题,可在Python调用时显式传递mode=None,明确告知f2py不传入该参数:
cpt.checkpoint(cpt=1, debug=debug, mode=None)
额外优化:给可选参数设置默认逻辑
在Fortran中给可选参数设置默认值,避免因present()判断异常导致错误:
subroutine checkpoint(cpt, debug, mode, file_name) implicit none integer, intent(in) :: cpt logical, intent(in) :: debug character(len=*), intent(in), optional :: mode character(len=*), intent(in), optional :: file_name character(len=30) :: def_name = 'checkpoint.dat' character(len=6) :: local_mode = 'VALUES' ! 设置默认模式 if(present(file_name)) def_name = file_name ! -- some code... if(present(mode)) then if(mode .eq. 'TIME' .or. mode .eq. 'VALUES') then local_mode = mode else stop "ERROR - Wrong checkpoint mode: must be one among 'VALUES','TIME'." end if end if ! 使用local_mode进行后续逻辑处理 ! ... end subroutine checkpoint
内容的提问来源于stack exchange,提问作者luca allegri
相关产品推荐
相关产品推荐

