如何从 Perl 调用命名参数 Python 函数?

问题描述 投票:0回答:3

我正在使用

Inline::Python
0.56,尝试从 Perl 调用带有命名参数的 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;

我的错误是:

TypeError: get_sbom_of_package() takes from 0 to 2 positional arguments but 8 were given at (eval 3) line 3.

我还需要做内联 Python 来了解我正在为其提供命名参数吗?我已将 Perl 中的调用替换为

my $sbp = get_sbom_of_package(
    $package ,
    $target_path
);

而且效果很好。我想要么是

  • 我的 Python 很糟糕或者
  • Inline::Python 配置问题
  • Inline::Python 限制

从最有可能到最不可能排序。 :-)

python perl inline
3个回答

1
投票

如果我正确读取 XS 并记住我的 Python 扩展模块工作,则这不是直接可能的。

Inline::Python
似乎使用
PyObject_CallObject
调用 py 可调用对象,它传递参数元组 - 没有任何命名/关键字参数。

因此,您必须自己完成此操作,也许可以通过在 py 可调用对象周围放置一个包装器,该包装器理解您所说的

parameter => value, ...
的含义并构造要传递的正确元组。当然,您还需要多余地了解默认值。您可能会 rev
Inline::Python
以支持询问可调用函数的签名以查找关键字参数...但是您仍然需要调整这些语义以适应普通 Perl 子例程自己调用。


1
投票

Note   这是为了勾画这样的想法:“命名参数”在 Perl 中实现为散列(ref)——> 在 Python 中实现字典,然后在 Python 端使用命名参数执行任何需要完成的操作手。无论如何,将其他需要的参数添加到列表(或字典)中,例如函数名称、数组引用或诸如此类的东西。

最终目的没有解释,但如果澄清的话我可以添加更具体的代码。 (脚注中给出了如何使用它的猜测,以及另一种相当通用的方式。


尝试的代码将四 (4) 个参数传递给 Perl 的函数调用, 而 Python 的函数被编写为采用两个参数(每个参数都有一个默认值)。

如果要将命名参数传递给 Python 函数,一种方法是传递字典。那么这也顺便模仿了你的 Perl 使用

def adict(d):
    for key in d:
        print("key:", key, "value:", d[key])

通过这种方式,可以将 Perl 中的调用者(哈希)中的命名参数映射到 Python(字典),将其留给在此包装器中构建的普通 python->python 调用。

那么你的代码可以是

use warnings;
use strict;
use feature 'say';

use Inline::Python;

my $package = 'thePackage';
my $target_path  = $ENV{HOME};

call_py( {  # note -- pass a hashref
    package_name => $package, target_path  => $target_path
} );

use Inline Python => <<'END_PY'
def call_py(d):
    for key in d:
        print(key + " => " + d[key])
    # ...
    # prepare and make other (python-to-python) calls as needed
END_PY

如果需要从 Python 函数进行特定的进一步调用(通过命名参数?),请展示它们的外观,我可以添加到这个简单的示例中。

请参阅下文,了解我对这个问题的意图的猜测。

此打印(我的路径经过编辑)

目标路径 => /...
package_name => 包

或者可以设计一个系统来传递 Perl 的四个参数并在 Python 中获取它们并将它们解释为名称 => 值对,但为什么呢?

一旦 Python 函数中的参数从字典中解压出来,以及可能添加到参数列表中的任何其他内容以及通过 hash(ref) 从 Perl 发送的命名参数的字典,就可以进一步生成 python -> python有需要请致电。


Perl 中的函数采用标量列表。时期。所以这个

func(package_name => $package, target_path  => $target_path)

甚至这个

my %ph = (package_name => $package, target_path  => $target_path);

func( %ph );

真的是这个吗

func('package_name', $package, 'target_path', $target_path)

fat comma”(

=>
)是一个逗号,因此它的左侧参数也被引用。


想象一下,这样做的目的是能够从 Perl 中调用 Python 中的一个很棒的

py_lib
,以某种方式通过“命名参数”(请澄清)。以下是一些猜测

use warnings;
use strict;
use feature 'say';

use Inline::Python;

my $package = 'thePackage';
my $target_path  = $ENV{HOME};

call_py({ package_name => $package, target_path => $target_path });

use Inline Python => <<'END_PY'
def call_py(d):
    print(d)
    # prepare and make other (python-to-python) calls as needed

    print("\nArgs with these names passed from Perl:")
    py_lib_kw( pack=d['package_name'], path=d['target_path'] )

    print("\nVariable number of named args passed from Perl:")
    py_lib_kwargs( **d )

def py_lib_kw(path=None, pack=None):
   print ("package is " + pack + " and path is " + path)

def py_lib_kwargs(**data):
    for val in data:
        print(val + " => " + data[val])

END_PY
© www.soinside.com 2019 - 2024. All rights reserved.