Python 从numpy.uint8数组中提取无符号字符
我有从python序列中提取数值的代码,它在大多数情况下运行良好,但不适用于numpy数组 当我试图提取一个无符号字符时,我会执行以下操作Python 从numpy.uint8数组中提取无符号字符,python,c++,numpy,boost-python,Python,C++,Numpy,Boost Python,我有从python序列中提取数值的代码,它在大多数情况下运行良好,但不适用于numpy数组 当我试图提取一个无符号字符时,我会执行以下操作 unsigned char val = boost::python::extract<unsigned char>(sequence[n]); 如何在C++中成功地提取一个无符号字符?我必须为numpy类型写入/注册特殊转换器吗?我宁愿使用与其他Python序列相同的代码,也不必编写使用 PyRayAbjult*/Cuff>的特殊代码。 < P
unsigned char val = boost::python::extract<unsigned char>(sequence[n]);
如何在C++中成功地提取一个无符号字符?我必须为numpy类型写入/注册特殊转换器吗?我宁愿使用与其他Python序列相同的代码,也不必编写使用<代码> PyRayAbjult*/Cuff>的特殊代码。 < P>可以从Python转换器登记一个自定义的Posith.python,它处理从NoPy数组标量转换,如
无符号字符
。来自python的自定义转换器注册包含三个部分:
- 检查
是否可转换的函数。返回PyObject
表示NULL
无法使用已注册的转换器PyObject
- 构造函数,它从<代码> PyObjult<代码>中构造C++类型。仅当
未返回converter(PyObject)
时,才会调用此函数NULL
- 将被构造的C++类型。
- 必须在将要使用NumPy C API的扩展模块的初始化过程中调用。根据扩展如何使用NumPy C API,可能需要执行其他导入要求
- 检查
是否为NumPy数组标量PyObject
- 获取标量数组的对象。数据类型描述符对象包含有关如何解释底层字节的信息。例如,其数据成员包含对应于C类型的
- 可用于从NumPy数组标量中提取C类型值
这是一个完整的例子,演示了使用Help类,即代码> Enable NojyPyLygRyLoad
#包括
#包括
#定义NPY\u否\u已弃用\u API NPY\u 1\u 7\u API\u版本
#包括
//模型函数。
///@将显式提取uint8\u t的简短实体模型函数
///来自Boost.Python对象。
boost::uint8\u t test\u generic\u uint8(boost::python::object)
{
返回boost::python::extract(object)();
}
///@brief-Mockup函数,用于uint8\u t的自动转换。
boost::uint8_t test_-specific_-uint8(boost::uint8_t value){返回值;}
///@brief Mokcup函数,用于int32\t的自动转换。
boost::int32_t test_specific_int32(boost::int32_t value){返回值;}
///@支持NumPy之间自动转换的简短转换器类型
//标量和C++类型。
模板
结构启用\u numpy\u标量\u转换器
{
启用标量转换器()
{
//在另一个应用程序中使用NumPy C API所需的NumPy调用
//扩展模块。
导入数组();
boost::python::converter::registry::push_back(
&可兑换的,
&建设,,
boost::python::type_id());
}
静态void*可转换(PyObject*对象)
{
//如果满足以下所有条件,则对象是可转换的:
//-是有效的对象。
//-是一个numpy数组标量。
//-其描述符类型与此转换器的类型匹配。
返回(
对象&&//有效
PyArray_CheckScalar(对象)&&&//Scalar
PyArray_DescrFromScalar(对象)->type_num==NumPyScalarType//Match
)
?对象//可以转换Python对象。
:NULL;
}
静态空洞构造(
PyObject*对象,
boost::python::converter::rvalue_from_python_stage1_data*data)
{
//获取转换器已分配的内存块的句柄
//用于C++类型。
名称空间python=boost::python;
typedef python::converter::rvalue_from_python_storage_type;
void*storage=reinterpret\u cast(数据)->storage.bytes;
//将数组标量类型直接提取到存储器中。
PyArray_ScalarAsCtype(对象、存储);
//设置为可转换以表示成功。
数据->可转换=存储;
}
};
BOOST_PYTHON_模块(示例)
{
名称空间python=boost::python;
//启用numpy标量转换。
启用标量转换器();
启用标量转换器();
//公开测试函数。
python::def(“test_generic_uint8”和test_generic_uint8);
python::def(“特定于测试的单元8”和特定于测试的单元8);
python::def(“特定于测试的\u int32”和特定于测试的\u int32);
}
互动使用:
导入numpy
>>>导入示例
>>>断言(42==example.test\u generic\u uint8(42))
>>>断言(42==example.test\u generic\u uint8(numpy.uint8(42)))
>>>断言(42==example.test\u-specific\u-uint8(42))
>>>断言(42==example.test\u-specific\u-uint8(numpy.uint8(42)))
>>>断言(42==example.test\u specific\u int32(numpy.int32(42)))
>>>例如,测试特定于int32(numpy.int8(42))
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ArgumentError:中的Python参数类型
示例.特定于测试的int32(numpy.int8)
与C++签名不匹配:
测试专用的int32(int)
>>>示例.测试\u通用\u uint8(numpy.int8(42))
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:没有注册转换器能够生成类型的C++值
来自此类型为numpy.int8的Python对象的未签名字符
从交互式用法中需要注意的几点:
- Python能够从
和numpy.uint8
Python对象中提取int
Boost::uint8\u t
enable\u numpy\u scalar\u转换器不支持促销。例如,
接受升级为test\u specific\u int32()
TypeError: No registered converter was able to produce a C++ rvalue of type unsigned char from this Python object of type numpy.uint8
#include <iostream> #include <boost/python.hpp> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION // http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api #define PY_ARRAY_UNIQUE_SYMBOL printnum_cpp_module_PyArray_API #include <numpy/arrayobject.h> #include <numpy/arrayscalars.h> /* * Boost python converter for numpy scalars, e.g. numpy.uint32(123). * Enables automatic conversion from numpy.intXX, floatXX * in python to C++ char, short, int, float, etc. * When casting from float to int (or wide int to narrow int), * normal C++ casting rules apply. * * Like all boost::python converters, this enables automatic conversion for function args * exposed via boost::python::def(), as well as values converted via boost::python::extract<>(). * * Copied from the VIGRA C++ library source code (MIT license). * http://ukoethe.github.io/vigra * https://github.com/ukoethe/vigra */ template <typename ScalarType> struct NumpyScalarConverter { NumpyScalarConverter() { using namespace boost::python; converter::registry::push_back( &convertible, &construct, type_id<ScalarType>()); } // Determine if obj_ptr is a supported numpy.number static void* convertible(PyObject* obj_ptr) { if (PyArray_IsScalar(obj_ptr, Float32) || PyArray_IsScalar(obj_ptr, Float64) || PyArray_IsScalar(obj_ptr, Int8) || PyArray_IsScalar(obj_ptr, Int16) || PyArray_IsScalar(obj_ptr, Int32) || PyArray_IsScalar(obj_ptr, Int64) || PyArray_IsScalar(obj_ptr, UInt8) || PyArray_IsScalar(obj_ptr, UInt16) || PyArray_IsScalar(obj_ptr, UInt32) || PyArray_IsScalar(obj_ptr, UInt64)) { return obj_ptr; } return 0; } static void construct( PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data) { using namespace boost::python; // Grab pointer to memory into which to construct the C++ scalar void* storage = ((converter::rvalue_from_python_storage<ScalarType>*) data)->storage.bytes; // in-place construct the new scalar value ScalarType * scalar = new (storage) ScalarType; if (PyArray_IsScalar(obj_ptr, Float32)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Float32); else if (PyArray_IsScalar(obj_ptr, Float64)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Float64); else if (PyArray_IsScalar(obj_ptr, Int8)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Int8); else if (PyArray_IsScalar(obj_ptr, Int16)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Int16); else if (PyArray_IsScalar(obj_ptr, Int32)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Int32); else if (PyArray_IsScalar(obj_ptr, Int64)) (*scalar) = PyArrayScalar_VAL(obj_ptr, Int64); else if (PyArray_IsScalar(obj_ptr, UInt8)) (*scalar) = PyArrayScalar_VAL(obj_ptr, UInt8); else if (PyArray_IsScalar(obj_ptr, UInt16)) (*scalar) = PyArrayScalar_VAL(obj_ptr, UInt16); else if (PyArray_IsScalar(obj_ptr, UInt32)) (*scalar) = PyArrayScalar_VAL(obj_ptr, UInt32); else if (PyArray_IsScalar(obj_ptr, UInt64)) (*scalar) = PyArrayScalar_VAL(obj_ptr, UInt64); // Stash the memory chunk pointer for later use by boost.python data->convertible = storage; } }; /* * A silly function to test scalar conversion. * The first arg tests automatic function argument conversion. * The second arg is used to demonstrate explicit conversion via boost::python::extract<>() */ void print_number( uint32_t number, boost::python::object other_number ) { using namespace boost::python; std::cout << "The number is: " << number << std::endl; std::cout << "The other number is: " << extract<int16_t>(other_number) << std::endl; } /* * Instantiate the python extension module 'printnum'. * * Example Python usage: * * import numpy as np * from printnum import print_number * print_number( np.uint8(123), np.int64(-456) ) * * ## That prints the following: * # The number is: 123 * # The other number is: -456 */ BOOST_PYTHON_MODULE(printnum) { using namespace boost::python; // http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api import_array(); // Register conversion for all scalar types. NumpyScalarConverter<signed char>(); NumpyScalarConverter<short>(); NumpyScalarConverter<int>(); NumpyScalarConverter<long>(); NumpyScalarConverter<long long>(); NumpyScalarConverter<unsigned char>(); NumpyScalarConverter<unsigned short>(); NumpyScalarConverter<unsigned int>(); NumpyScalarConverter<unsigned long>(); NumpyScalarConverter<unsigned long long>(); NumpyScalarConverter<float>(); NumpyScalarConverter<double>(); // Expose our C++ function as a python function. def("print_number", &print_number, (arg("number"), arg("other_number"))); }