Boost:: Python-можно автоматически конвертировать из dict --> std:: map?
у меня есть класс C++ с функцией-членом, которая может принимать от малого до большого количества параметров. Назовем эти параметры a-f. Все параметры имеют значения по умолчанию. В рамках проекта python, над которым я работаю, я хочу предоставить этот класс python. В настоящее время функция-член выглядит примерно так:
class myClass {
public:
// Constructors - set a-f to default values.
void SetParameters(std::map<std::string, double> &);
private:
double a, b, c, d, e, f;
}
void myClass::SetParameters(std::map<std::string, double> const& params) {
// Code to iterate over the map, and set any found key/value pairs to their
// corresponding variable. i.e.- "a" --> 2.0, would set myClass::a to 2.0
}
В идеале, в Python, я хотел бы выполнить это с помощью dict:
>>> A = myModule.myClass();
>>> A.SetParameters({'a': 2.2, 'd': 4.3, b: '9.3'})
таким образом, пользователь может ввести значения в любой заказ и введите любое число из них перекрывается. Любые мысли о том, как это можно сделать в boost::python? Мне кажется, что я могу сделать это, изменив ввод карты на объект boost::python и используя функции извлечения. Однако это потребует от меня изменения интерфейса моей библиотеки (я бы предпочел сохранить интерфейс std::map и иметь некоторую технику промежуточного/автоматического преобразования для версии python). Мысли?
3 ответов
Я думаю, что есть несколько способов, которые легче выполнить, чем написать свой собственный конвертер. Вы можете использовать boost::python map_indexing_suite для преобразования для вас, или вы можете использовать аргументы ключевых слов в python. Я лично предпочитаю аргументы ключевых слов, так как это более "Питонический" способ сделать это.
Итак, это ваш класс (я добавил typedef для карты):
typedef std::map<std::string, double> MyMap;
class myClass {
public:
// Constructors - set a-f to default values.
void SetParameters(MyMap &);
private:
double a, b, c, d, e, f;
};
пример использования map_indexing_suite:
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
using boost::python;
BOOST_PYTHON_MODULE(mymodule)
{
class_<std::map<std::string, double> >("MyMap")
.def(map_indexing_suite<std::map<std::wstring, double> >() );
class_<myClass>("myClass")
.def("SetParameters", &myClass::SetParameters);
}
пример использования ключевого слова аргументы. Для этого требуется использовать оболочку raw_function:
using namespace boost::python;
object SetParameters(tuple args, dict kwargs)
{
myClass& self = extract<myClass&>(args[0]);
list keys = kwargs.keys();
MyMap outMap;
for(int i = 0; i < len(keys); ++i) {
object curArg = kwargs[keys[i]];
if(curArg) {
outMap[extract<std::string>(keys[i])] = extract<double>(kwargs[keys[i]]);
}
}
self.SetParameters(outMap);
return object();
}
BOOST_PYTHON_MODULE(mymodule)
{
class_<myClass>("myClass")
.def("SetParameters", raw_function(&SetParameters, 1));
}
это позволяет вам писать такие вещи в Python:
A.SetParameters(a = 2.2, d = 4.3, b = 9.3)
этот блог есть довольно четкое описание того, как писать эти преобразователи. Основной шаблон заключается в определении класса, который имеет форму:
struct SomeType_from_PyObject
{
SomeType_from_PyObject();
static void* convertible(PyObject* obj_ptr);
static void construct(PyObject* obj_ptr,
converter::rvalue_from_python_stage1_data* data);
};
где конструктор отвечает за добавление этого конвертера в Boost.Реестр Python:
SomeType_from_PyObject::SomeType_from_PyObject()
{
converter::registry::push_back(&convertible,
&construct,
type_id<SomeType>());
}
функции convertible
сообщает Boost, может ли этот конвертер преобразовать указанный объект Python:
void* SomeType_from_PyObject::convertible(PyObject* obj_ptr)
{
if (PyMapping_Check(obj_ptr)) {
return obj_ptr;
} else {
return NULL;
}
}
на construct
функция фактически создает объект тип преобразования:
void SomeType_from_PyObject::construct(PyObject* obj_ptr,
converter::rvalue_from_python_stage1_data* data)
{
typedef converter::rvalue_from_python_storage<SomeType> storage_t;
storage_t* the_storage = reinterpret_cast<storage_t*>(data);
void* memory_chunk = the_storage->storage.bytes;
object obj(handle<>(borrowed(obj_ptr)));
SomeType* output = new (memory_chunk) SomeType();
// Use the contents of obj to populate output, e.g. using extract<>
data->convertible = memory_chunk;
}
а затем в вашем внутри вашего BOOST_PYTHON_MODULE, включите строку
SomeType_from_PyObject();
Я просто намочил пальцы ног с boost:: python, поэтому не могу полностью ответить на ваш вопрос. Но первый блокпост, который я вижу, гарантирует, что ключи py dict-это все строки. Python dicts также можно использовать в кортежах (и я предполагаю больше типов).