从boost::python::object列表中获取单个元素以在Python例程中使用
我有一个C++的Boost Python对象,这个对象是一个Python列表的封装。
PyObject * pyList = func(...);
boost::python::object listObj(handle<>(boost::python::borrowed(pyList)));
我可以通过一些操作来确认它确实是一个列表,比如说:
boost::python::object np = import("numpy");
boost::python::np_difference = np.attr("diff");
np_difference(listObj);
for(int i=0; i<len(listObj); i++){
double value = boost::python::extract<double>(listObj[i]);
cout << i << " " << value << endl;
}
这个操作会把第i个元素减去第i-1个元素,然后创建一个新的列表,接着把每个元素提取出来并在C++中打印到标准输出。
我想做的是用这个列表对象来调用我定义的打印函数:
boost::python::object print = std.attr("print");
但我只想打印我指定的某个元素。在Python中,我只需要写:
print myList[0]
因为它就是一个普通的Python列表。但是当我在C++中用Boost Python尝试:
print(listObj[0]);
时,我得到了:
Error in Python: <type 'exceptions.TypeError'>: No to_python (by-value) converter found for C++ type: boost::python::api::proxy<boost::python::api::item_policies>.
那么,我该如何从Python列表对象中访问单个元素,并在C++中像上面那样调用Python的打印方法(或者任何其他需要字符串作为输入的Python函数)呢?
2 个回答
0
编辑
Tanner Sansbury 的回答是用 C++ 的方式来解决这个问题,而我下面介绍的方法只是一个变通办法,它可以让你把一个 Python 对象放到 boost::python 命名空间中,然后再赋值到 __main__ 的 Python 解释器命名空间里。
明白了。从这里得到的启发,我们需要把 boost::python::object 赋值到 Python 的命名空间,也就是:
boost::python::object main_module = boost::python::import("__main__");
boost::python::object main_namespace = main_module.attr("__dict__");
main_module.attr("myList") = listObj;
boost::python::exec("print myList", main_namespace);
希望这对你有帮助。
5
boost::python::object
的 operator[]
方法会返回一个 boost::python::proxy
对象。虽然 proxy
类可以隐式转换为 boost::python::object
,但在很多地方的API中,还是需要明确的转换。
如果你想从 proxy
明确构造一个 boost::python::object
,这样可以解决转换异常:
print(boost::python::object(listObjString[0]));
下面是一个完整的嵌入式Python示例,演示如何通过以下方式打印列表中的单个元素:
- 使用Python内置的
print
函数 - 使用Python/C API中的
PyObject_Print()
函数 - 通过
__str__
提取对象的字符串表示,并用std::cout
打印
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/range/irange.hpp>
/// @brief Default flag to have PyObject_Print use the object's
/// __str__ method. The python.h files only define the flag for
/// __repr__.
#define Py_PRINT_STR 0
int main()
{
Py_Initialize();
namespace python = boost::python;
try
{
// Create and populate a Python list.
// >>> list = [x for x in range(100, 103)]
python::list list;
BOOST_FOREACH(int x, boost::irange(100, 103))
list.append(x);
// The proxy returned from a Boost.Python's operator[] provides a
// user-defined conversion to a Boost.Python object. In most cases,
// explicitly invoking the conversion is required.
// Print list[0] using the built-in function print.
/// >>> getattr(__builtins__, 'print')(list[0])
python::object print =
python::import("__main__").attr("__builtins__").attr("print");
print(python::object(list[0]));
// Print list[1] using the Python/C API.
// >>> import sys; sys.stdout.write(list[1].__str__())
PyObject_Print(python::object(list[1]).ptr(), stdout, Py_PRINT_STR);
std::cout << std::endl;
// Print list[2] using the result of the object's __str__ method, and
// extract a C++ string.
std::cout << python::extract<std::string>(
python::object(list[2]).attr("__str__")())() << std::endl;
}
catch (python::error_already_set&)
{
PyErr_Print();
}
}
输出:
100
101
102