Вопрос

I have a C++ class that I'm building into a python module using boost::python. I have a few functions that I want to take keyword arguments. I've set up wrapper functions to pass to raw_arguments and that works fine, but I want to build in some error checking for the function arguments. Is there a standard way to do this?

My function prototype, in C++, looks a bit like this:

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

The third argument is optional, with a default value of 0 (I've implemented this in boost::python using macros up till now). In python, I want to be able to achieve the following behaviour:

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

Is there something in boost::python or the raw_function wrapper that can facilitate this, or do I need to write the code to check all this myself? If I do need to, how can I raise the exceptions? Is there a standard way of doing this?

Это было полезно?

Решение

The boost/python/args.hpp file provides a family of classes for specifying argument keywords. In particular, Boost.Python provides an arg type, that represents a potential keyword argument. It overloads the comma operator to allow for a more natural definition of an argument list.

Exposing myFunction on MyClass as my_function, where a, b, and c are keyword arguments, and c has a default value of 0 could be written as follows:

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))
    ;
}

Here is a complete example:

#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))
    ;
}

Interactive Usage:

>>> 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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top