Извлечение аргументов из kwargs в boost::python

У меня есть класс С++, который я встраиваю в модуль Python, используя boost::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, что может облегчить это, или мне нужно написать код, чтобы проверить все это самому? Если мне нужно, как я могу вызвать исключения? Есть ли стандартный способ сделать это?


person orentago    schedule 20.05.2013    source источник


Ответы (1)


Файл boost/python/args.hpp предоставляет семейство классы для указания ключевых слов аргументов. В частности, Boost.Python предоставляет arg, представляющий потенциальный аргумент ключевого слова. Он перегружает оператор запятой, чтобы обеспечить более естественное определение списка аргументов.

Представление myFunction в MyClass как my_function, где a, b и c являются аргументами ключевого слова, а 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)
person Tanner Sansbury    schedule 21.05.2013
comment
Это сработало отлично, и немного неловко, что я невольно использовал аналогичную настройку для другой функции, чтобы перегрузить аргументы этой функции. Это работает и для конструкторов? - person orentago; 21.05.2013
comment
Чтобы ответить на мой собственный вопрос: да, это так. Сделайте py::init‹Перечислите типы аргументов›( (py::arg(a), py::arg(b)...)) в объявлении класса кода-оболочки. - person orentago; 21.05.2013
comment
(Если у кого-то возникли проблемы с выполнением этой работы, обратите внимание на дополнительные круглые скобки, окружающие аргументы) - person ricab; 04.02.2015
comment
В вашем примере именованные аргументы всегда находятся в одном и том же «естественном» порядке (a, b, c). Думаю, это тоже должно работать: assert(6 == my_class.my_function(c=3, a=2, b=1)), верно? - person fcatho; 09.09.2019