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

oxiaedzo  于 2022-11-15  发布在  Perl
关注(0)|答案(3)|浏览(223)

我正在使用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执行其他操作以理解我正在向它提供命名参数?

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

而且效果很好我想要么是

  • 坏的Python或者
  • Inline::Python配置问题
  • 内联::Python限制

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

2w3rbyxf

2w3rbyxf2#

如果我正确地阅读了XS并记住了Python扩展模块的工作,这是不可能的。
Inline::Python似乎使用PyObject_CallObject来调用py可调用对象,PyObject_CallObject传递一个参数元组-没有任何命名/关键字参数。
因此,您必须自己完成,可能需要在py可调用对象周围放置一个 Package 器,该 Package 器理解parameter => value, ...的含义,并构造正确的元组来沿着。您还需要冗余地了解默认值,您可能需要修改Inline::Python以支持查询可调用对象的签名来查找关键字参数...我仍然必须自己修改那些语义以适应普通的Perl子例程调用。

gojuced7

gojuced73#

备注 这意味着,“命名参数”在Perl中被实现为哈希(ref)--〉在Python中被实现为字典,然后在Python端用命名参数做任何需要做的事情。无论如何,把其他需要的参数添加到列表(或者字典)中,比如函数名、数组引用等等。

  • 没有解释最终的目的,但是如果能解释清楚,我可以添加更具体的代码。(脚注中给出了一个关于如何使用它的猜测,以及另一个相当通用的方法)*

尝试的代码向Perl的函数调用传递了4个参数,†而Python的函数被编写为接受2个参数(每个参数都有一个默认值)。
如果要将命名参数传递给Python函数,一种方法是传递字典。

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

这种方法可以将Perl中调用者的命名参数(哈希)Map到Python(字典),让普通的python-〉python调用在这个 Package 器中构建。
那么你的代码可以是

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函数中进行特定的进一步调用(通过命名参数?),请展示它们的外观,我可以添加到这个简单的示例中。
下面是我对这个问题的猜测,请澄清一下。
这将打印(编辑了我的路径)

target_path => /...
package_name => thePackage

或者可以设计一个系统来传递Perl的四个参数,并在Python中接受它们,并将它们解释为name =〉value对,但为什么呢?
一旦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)

这个“胖逗号”(=>)是一个逗号,它的左参数也被引用。
[3]假设这样做的目的是通过“命名参数”(请澄清),从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

相关问题