提振.Python自定义转换器
Boost.Python custom converter
我有一个以向量为参数的类(二进制文件内容)。
我想将python 'str'类型转换为unsigned char的向量,但只适用于我的一个类方法。
BOOST_PYTHON_MODULE(hello) { class_<Hello>("Hello").
// This method takes a string as parameter and print it
.def("printChar", &Hello::printChar)
// This method takes a vector<unsigned char> parameter
.def("storeFile", &Hello::storeFile) }
使用自定义转换器似乎是我需要的,但如果我修改我的boost::python::converter::注册表,它将被修改为我对printChar的所有调用,所有python方法传递字符串作为参数将被转换为向量。
如何注册每个方法的转换器?
解决这个问题有两种方法:
- 导出一个辅助函数为
Hello.storeFile
,接受boost::python::str
,从字符串中构造std::vector<unsigned char>
,委托给c++Hello::storeFile
成员函数。 编写自定义转换器。虽然转换器不能以每个函数为基础进行注册,但它们的作用域相当好,不会执行任何意外的转换。这种方法通常提供更多的可重用性。
Helper函数
使用辅助函数不会影响任何其他导出函数。因此,python字符串和std::vector<unsigned char>
之间的转换只会发生在Hello.storeFile
上。
void Hello_storeFile(Hello& self, boost::python::str str)
{
std::cout << "Hello_storeFile" << std::endl;
// Obtain a handle to the string.
const char* begin = PyString_AsString(str.ptr());
// Delegate to Hello::storeFile().
self.storeFile(std::vector<unsigned char>(begin, begin + len(str)));
}
...
BOOST_PYTHON_MODULE(hello)
{
namespace python = boost::python;
python::class_<Hello>("Hello")
// This method takes a string as parameter and print it
.def("printChar", &Hello::printChar)
// This method takes a vector<unsigned char> parameter
.def("storeFile", &Hello_storeFile)
;
}
自定义转换器
转换器注册有三个部分:
- 检查
PyObject
是否可转换的函数。返回NULL
表示PyObject
不能使用注册的转换器。 - 从
PyObject
构造c++类型的构造函数。这个函数只有在converter(PyObject)
没有返回NULL
时才会被调用。 - 要构造的c++类型。
因此,对于给定的c++类型,如果converter(PyObject)
返回一个非NULL
的值,那么construct(PyObject)
将创建c++类型。c++类型充当进入注册表的键,所以Boost。Python不应该执行非预期的转换。
在这个问题的上下文中,我们想要一个std::vector<unsigned char>
的转换器,如果PyObject
是PyString
, converter(PyObject)
将返回非NULL
, converter(PyObject)
将使用PyObject
来创建和填充std::vector<unsigned char>
。只有当导出的c++函数具有std::vector<unsigned char>
(或const引用)形参并且python提供的实参是字符串时,才会发生此转换。因此,这个自定义转换器不会影响具有std::string
参数的导出函数。
下面是一个完整的例子。我选择使转换器通用,以允许从python字符串构造多个类型。有了它的链支持,它应该有和其他Boost一样的感觉。Python类型。
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/python.hpp>
class Hello
{
public:
void printChar(const std::string& str)
{
std::cout << "printChar: " << str << std::endl;
}
void storeFile(const std::vector<unsigned char>& data)
{
std::cout << "storeFile: " << data.size() << ": ";
BOOST_FOREACH(const unsigned char& c, data)
std::cout << c;
std::cout << std::endl;
}
};
/// @brief Type that allows for conversions of python strings to
// vectors.
struct pystring_converter
{
/// @note Registers converter from a python interable type to the
/// provided type.
template <typename Container>
pystring_converter&
from_python()
{
boost::python::converter::registry::push_back(
&pystring_converter::convertible,
&pystring_converter::construct<Container>,
boost::python::type_id<Container>());
return *this;
}
/// @brief Check if PyObject is a string.
static void* convertible(PyObject* object)
{
return PyString_Check(object) ? object : NULL;
}
/// @brief Convert PyString to Container.
///
/// Container Concept requirements:
///
/// * Container::value_type is CopyConstructable from char.
/// * Container can be constructed and populated with two iterators.
/// I.e. Container(begin, end)
template <typename Container>
static void construct(
PyObject* object,
boost::python::converter::rvalue_from_python_stage1_data* data)
{
namespace python = boost::python;
// Object is a borrowed reference, so create a handle indicting it is
// borrowed for proper reference counting.
python::handle<> handle(python::borrowed(object));
// Obtain a handle to the memory block that the converter has allocated
// for the C++ type.
typedef python::converter::rvalue_from_python_storage<Container>
storage_type;
void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
// Allocate the C++ type into the converter's memory block, and assign
// its handle to the converter's convertible variable. The C++
// container is populated by passing the begin and end iterators of
// the python object to the container's constructor.
const char* begin = PyString_AsString(object);
data->convertible = new (storage) Container(
begin, // begin
begin + PyString_Size(object)); // end
}
};
BOOST_PYTHON_MODULE(hello)
{
namespace python = boost::python;
// Register PyString conversions.
pystring_converter()
.from_python<std::vector<unsigned char> >()
.from_python<std::list<char> >()
;
python::class_<Hello>("Hello")
// This method takes a string as parameter and print it
.def("printChar", &Hello::printChar)
// This method takes a vector<unsigned char> parameter
.def("storeFile", &Hello::storeFile)
;
}
和示例用法:
>>> from hello import Hello
>>> h = Hello()
>>> h.printChar('abc')
printChar: abc
>>> h.storeFile('def')
storeFile: 3: def
>>> h.storeFile([c for c in 'def'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
Hello.storeFile(Hello, list)
did not match C++ signature:
storeFile(Hello {lvalue}, std::vector<unsigned char,
std::allocator<unsigned char> >)
有关自定义转换器和c++容器的更多信息,请考虑阅读此回答
- std::设置自定义比较器
- 如何正确实现和访问运算符的各种自定义枚举器
- 跟随整数索引列表的自定义类迭代器
- 带自定义比较器的最小优先级队列
- 将字符串转换为自定义类
- 将 OpenGL 坐标系统转换为自定义并返回
- C 功能指针用于将QVariant转换为{自定义类型
- C#二进制编写器自定义
- QList 作为 qt 设计器自定义小部件中的一个属性
- 将字符串向量转换为自定义对象向量
- Qt/C++在不使用dynamic_Cast的情况下将QGraphicsItem转换为自定义QGraphicsItem
- 自定义迭代器和自定义常量迭代器之间的转换
- 使用boost将UTC时间转换为自定义时区
- gsoap将anyAttribute转换为自定义类型
- 如何将LRESULT强制转换为自定义结构类型
- 提振.Python自定义转换器
- 将基于自定义模板的迭代器类对象转换为const_iterator
- 自动调用原始指针的自定义转换器 A* <-> B*
- 从浮点转换为自定义数字类型
- 将v8对象转换为自定义c++对象