如何在Perl中调用带命名参数的Python函数?
问题描述
我正在使用Inline::Python 0.56,尝试从Perl中调用带命名参数的Python函数。替换为可运行示例代码后,用命名参数调用时报错:
TypeError: get_sbom_of_package() takes from 0 to 2 positional arguments but 8 were given at (eval 3) line 3.
改用位置参数调用则运行正常。我猜测原因可能是自身Python代码问题、Inline::Python配置问题或其功能限制,按可能性从高到低排序,寻求解决方案。
示例代码如下:
use strict; use warnings; use 5.16.3; use Inline Python => <<'END_OF_PYTHON_CODE'; # Interface def get_sbom_of_package ( package_name = None, target_path = None, ): assert package_name is not None assert target_path is not None print ( package_name, target_path ) return package_name END_OF_PYTHON_CODE my $package = 'thePackage'; my $target_path = $ENV{HOME}; # 报错的调用方式 my $sbp = get_sbom_of_package( package_name => $package , target_path => $target_path ); say $sbp;
原因分析(按可能性从高到低)
Inline::Python参数映射机制限制:这是核心原因。Perl中key => value的命名参数语法会被解析为扁平化的列表传递给Python函数,而非直接映射为Python的关键字参数。比如package_name => $package会被拆成两个独立的位置参数,最终传递给Python函数的参数数量远超预期,触发类型错误。- Python函数默认参数的兼容性问题:虽然函数写法符合Python规范,但
Inline::Python对带默认值的参数处理可能存在隐性兼容问题,但位置参数调用正常,所以该可能性较低。 Inline::Python配置缺失:目前Inline::Python官方文档未提及需要特殊配置来支持关键字参数映射,因此该可能性最低。
解决方案
方法1:通过哈希引用传递并在Python中解包
将Perl的命名参数封装为哈希引用,Python函数接收后解析为关键字参数:
修改后的完整代码:
use strict; use warnings; use 5.16.3; use Inline Python => <<'END_OF_PYTHON_CODE'; # Interface def get_sbom_of_package(args): package_name = args.get('package_name') target_path = args.get('target_path') assert package_name is not None assert target_path is not None print(package_name, target_path) return package_name END_OF_PYTHON_CODE my $package = 'thePackage'; my $target_path = $ENV{HOME}; # 用哈希引用传递命名参数 my $sbp = get_sbom_of_package({ package_name => $package , target_path => $target_path }); say $sbp;
方法2:添加Python适配函数转换参数
在Python层封装一个适配函数,接收Perl传递的键值对列表,转换为关键字参数调用原函数:
修改后的完整代码:
use strict; use warnings; use 5.16.3; use Inline Python => <<'END_OF_PYTHON_CODE'; # 原函数保持不变 def get_sbom_of_package(package_name = None, target_path = None): assert package_name is not None assert target_path is not None print(package_name, target_path) return package_name # 适配Perl的参数传递方式 def perl_get_sbom(*args): kwargs = dict(zip(args[::2], args[1::2])) return get_sbom_of_package(**kwargs) END_OF_PYTHON_CODE my $package = 'thePackage'; my $target_path = $ENV{HOME}; # 调用适配函数 my $sbp = perl_get_sbom( package_name => $package , target_path => $target_path ); say $sbp;
方法3:直接使用位置参数(临时方案)
如果不需要保留命名参数的可读性,直接用位置参数调用即可正常运行:
my $sbp = get_sbom_of_package($package, $target_path);
内容的提问来源于stack exchange,提问作者mpersico
相关产品推荐
相关产品推荐

