从 boost::python::object 列表中获取单个元素,用于 python 例程

Posted

技术标签:

【中文标题】从 boost::python::object 列表中获取单个元素,用于 python 例程【英文标题】:Get single element from a boost::python::object list, for use in python routine 【发布时间】:2014-03-26 22:56:21 【问题描述】:

我有一个用于 Python 列表的 c++ boost python 对象(PyObject * 上的 boost 包装器),

  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-1 元素中减去第 i 个元素并创建一个新列表,然后提取其中的每个元素并在 C++ 中打印到标准输出。

我想做的是将此 listObj 与我定义为的打印功能一起使用

boost::python::object print = std.attr("print");    

但我只想打印我指定的元素之一。在python中我只会写

print myList[0]

因为它只是一个 python 列表。但是当我尝试

print(listObj[0]);

在 c++ 中使用 boost python 我得到了

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 列表对象访问单个元素并在 python 调用中使用它,如上面的 print 方法(或任何其他接受字符串作为输入的 python 函数)在 c++ 中?

【问题讨论】:

【参考方案1】:

boost::python::objectoperator[] 返回一个 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

【讨论】:

这正是我想要做的。我下面的方法实现了类似的结果,但是了解 boost::python::object 的 operator[] 的功能是一个更好的解决方案,也是我最终想知道的。【参考方案2】:

编辑 Tanner Sansbury 的答案是解决问题的 C++ 方法,我在下面介绍的方法只是一种解决方法,它允许您将 boost::python 命名空间中的 python 对象分配给 __main__ python 解释器命名空间。


知道了。受here 启发,需要将 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);  

希望这会有所帮助。

【讨论】:

以上是关于从 boost::python::object 列表中获取单个元素,用于 python 例程的主要内容,如果未能解决你的问题,请参考以下文章

相当于存储 boost::python::object 的 SWIG

如何使用 Boost Python 从 C++ bool 转换为 Python boolean?

提取基类指针

提升 Python 哈希

从三个源列获取时从目标列返回输出

pyspark:从现有列创建 MapType 列