pybind 如何操作 py::list 对象
pybind how can I operate over a py::list object
为了更好地理解如何使用 pybind 库将参数从 Python 传递到 C++ 函数,我想构建一个小的 dummy/demo 代码,我可以在其中接收 Python在 C++ 端列出,将其转换为浮点指针对象,然后打印它。
虽然我知道我可以使用 py::list
class 我还没有想出这个 class 的可用方法。我查看了文档参考,然后查看了代码 (list.h、stl.h),但无法确定哪些方法可用。
__getitem__
等价于什么? py::list
的每个 python 方法都有吗?
您要找的代码是here:
class list : public object {
public:
PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)
explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate list object!");
}
size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
detail::list_iterator begin() const { return {*this, 0}; }
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
template <typename T> void append(T &&val) const {
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
}
};
还要记住,py::list
继承自 py::object
,后者又继承自 py::handle
(这也意味着您正在通过引用传递)。根据我的经验,这种用法的文档很少,阅读代码是最好的选择。
从class定义可以看出,我们可以使用成员函数size
、operator[]
、begin
、end
(C++迭代器! ) 和 append
(模板化!)。如果这还不够,您可以使用 attr
to access python attributes(包括方法)。这是一个例子:
Python代码(some_python.py
):
import cppimport
cpp = cppimport.imp("some_cpp")
l = [1,2,3,4,5]
cpp.test(l)
print('after C++', l)
cpp.float_cast(l)
C++代码(some_cpp.cpp
):
/* <%
setup_pybind11(cfg)
%> */
#include <pybind11/pybind11.h>
#include <iostream>
#include <string>
namespace py = pybind11;
void test(py::list l) {
l.attr("pop")();
std::cout << "List has length " << l.size() << std::endl;
for (py::handle obj : l) { // iterators!
std::cout << " - " << obj.attr("__str__")().cast<std::string>() << std::endl;
}
l.append(10); // automatic casting (through templating)!
}
void float_cast(py::list l) {
float f = l.cast<float>();
}
PYBIND11_MODULE(some_cpp, m) {
m.def("test", &test);
m.def("float_cast", &float_cast);
}
输出:
List has length 4
- 1
- 2
- 3
- 4
after C++ [1, 2, 3, 4, 10]
Traceback (most recent call last):
File "some_python.py", line 9, in <module>
cpp.float_cast(l)
RuntimeError: Unable to cast Python instance to C++ type (compile in debug mode for details)
如您所见,我还包括了您关于转换为浮点数的具体问题。这里我使用了 py::handle
的 cast
方法,它给出了一个很好的例外。您可以尝试 "directly" 投射对象(类似于 float* f = (float*) &l;
),但这会给您带来垃圾,我想这不是您要找的东西。
还有一点要注意:pybind/stl.h
可以在 Python 的标准类型和 C++ 版本之间进行转换。例如,list
可能会转换为 std::vector<int>
,包括类型检查。这样做的一个重要影响是数据作为 copy 而不是作为引用传递。
为了更好地理解如何使用 pybind 库将参数从 Python 传递到 C++ 函数,我想构建一个小的 dummy/demo 代码,我可以在其中接收 Python在 C++ 端列出,将其转换为浮点指针对象,然后打印它。
虽然我知道我可以使用 py::list
class 我还没有想出这个 class 的可用方法。我查看了文档参考,然后查看了代码 (list.h、stl.h),但无法确定哪些方法可用。
__getitem__
等价于什么? py::list
的每个 python 方法都有吗?
您要找的代码是here:
class list : public object {
public:
PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)
explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate list object!");
}
size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
detail::list_iterator begin() const { return {*this, 0}; }
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
template <typename T> void append(T &&val) const {
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
}
};
还要记住,py::list
继承自 py::object
,后者又继承自 py::handle
(这也意味着您正在通过引用传递)。根据我的经验,这种用法的文档很少,阅读代码是最好的选择。
从class定义可以看出,我们可以使用成员函数size
、operator[]
、begin
、end
(C++迭代器! ) 和 append
(模板化!)。如果这还不够,您可以使用 attr
to access python attributes(包括方法)。这是一个例子:
Python代码(some_python.py
):
import cppimport
cpp = cppimport.imp("some_cpp")
l = [1,2,3,4,5]
cpp.test(l)
print('after C++', l)
cpp.float_cast(l)
C++代码(some_cpp.cpp
):
/* <%
setup_pybind11(cfg)
%> */
#include <pybind11/pybind11.h>
#include <iostream>
#include <string>
namespace py = pybind11;
void test(py::list l) {
l.attr("pop")();
std::cout << "List has length " << l.size() << std::endl;
for (py::handle obj : l) { // iterators!
std::cout << " - " << obj.attr("__str__")().cast<std::string>() << std::endl;
}
l.append(10); // automatic casting (through templating)!
}
void float_cast(py::list l) {
float f = l.cast<float>();
}
PYBIND11_MODULE(some_cpp, m) {
m.def("test", &test);
m.def("float_cast", &float_cast);
}
输出:
List has length 4
- 1
- 2
- 3
- 4
after C++ [1, 2, 3, 4, 10]
Traceback (most recent call last):
File "some_python.py", line 9, in <module>
cpp.float_cast(l)
RuntimeError: Unable to cast Python instance to C++ type (compile in debug mode for details)
如您所见,我还包括了您关于转换为浮点数的具体问题。这里我使用了 py::handle
的 cast
方法,它给出了一个很好的例外。您可以尝试 "directly" 投射对象(类似于 float* f = (float*) &l;
),但这会给您带来垃圾,我想这不是您要找的东西。
还有一点要注意:pybind/stl.h
可以在 Python 的标准类型和 C++ 版本之间进行转换。例如,list
可能会转换为 std::vector<int>
,包括类型检查。这样做的一个重要影响是数据作为 copy 而不是作为引用传递。