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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:35:30