从kwargs中提取参数在boost::python中的应用

8

我有一个C++类,正在使用boost::python构建成Python模块。我有几个函数需要接收关键字参数。我已经设置了包装函数来传递给raw_arguments,这样可以正常工作,但我希望为函数参数构建一些错误检查。是否有标准的方法可以实现这个目的?

我的函数原型在C++中看起来像这样:

double MyClass::myFunction(int a, int b, int c);

第三个参数是可选的,默认值为0(我目前使用boost::python宏实现)。在Python中,我希望能够实现以下行为:
MyClass.my_function(1) # Raises exception
MyClass.my_function(2, 3) # So that a = 2, b = 3 and c defaults to 0
MyClass.my_function(2, 3, 1) # As above, but now c = 1
MyClass.my_function(2, 3, 1, 3) # Raises exception
MyClass.my_function(3, 1, c = 2) # So a = 3, b = 1 and c = 2
MyClass.my_function(a = 2, b = 2, c = 3) # Speaks for itself
MyClass.my_function(b = 2, c = 1) # Raises exception

在boost::python或raw_function包装器中是否有可以简化这个过程的内容,还是我需要自己编写代码来进行检查? 如果需要,我该如何引发异常? 有没有标准的方法可以做到这一点?

1个回答

15

boost/python/args.hpp文件提供了一组用于指定参数关键字的类。特别地,Boost.Python提供了一个arg类型,表示一个可能的关键字参数。它重载了逗号运算符,允许更自然地定义参数列表。

myFunctionMyClass上公开为my_function,其中abc是关键字参数,而c具有默认值0,可以按以下方式编写:

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<MyClass>("MyClass")
    .def("my_function", &MyClass::myFunction,
         (python::arg("a"), "b", python::arg("c")=0))
    ;
}

这里是一个完整的示例:

#include <boost/python.hpp>

class MyClass
{
public:
  double myFunction(int a, int b, int c)
  {
    return a + b + c;
  }
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<MyClass>("MyClass")
    .def("my_function", &MyClass::myFunction,
         (python::arg("a"), "b", python::arg("c")=0))
    ;
}

交互使用:

>>> import example
>>> my_class = example.MyClass()
>>> my_class.my_function(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    MyClass.my_function(MyClass, int)
did not match C++ signature:
    my_function(MyClass {lvalue}, int a, int b, int c=0)
>>> assert(5 == my_class.my_function(2, 3))
>>> assert(6 == my_class.my_function(2, 3, 1))
>>> my_class.my_function(2, 3, 1, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    MyClass.my_function(MyClass, int, int, int, int)
did not match C++ signature:
    my_function(MyClass {lvalue}, int a, int b, int c=0)
>>> assert(6 == my_class.my_function(3, 1, c=2))
>>> assert(7 == my_class.my_function(a=2, b=2, c=3))
>>> my_class.my_function(b=2, c=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    MyClass.my_function(MyClass)
did not match C++ signature:
    my_function(MyClass {lvalue}, int a, int b, int c=0)

那个完美地运作了,有点令人尴尬的是,我无意中在另一个函数上使用了类似的设置来重载该函数的参数。这对构造函数也适用吗? - orentago
回答我的问题:是的,它可以。在包装器代码类声明中执行 py::init<List your argument types>( (py::arg("a"), py::arg("b")...) )。 - orentago
1
(如果有人无法使其工作,请注意args周围的额外括号) - ricab
在你的例子中,命名参数总是按照相同的“自然”顺序(a,b,c)。我想这也可以工作:assert(6 == my_class.my_function(c=3, a=2, b=1)),对吗? - fcatho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接