Pybind11 - 绑定类方法返回新的类实例,而不是就地编辑

问题描述 投票:0回答:1

我无法将类方法的输入(输入:单独类的特定实例)返回给Python。绑定编译后,我可以在 Python 中使用生成的模块。然而,类方法应该返回与其承认的相同的实例(经过一些处理后)。

Obstacle
类用作输入。
ObstacleProcess
类有一个处理输入(
__call__
的实例)的方法(Python:
operator_py
/ C++:
Obstacle
)。以下 Python 代码显示返回
Obstacle
的不同实例:

import example

obstacle_1 = example.Obstacle()
obstacle_2 = example.Obstacle()

obstacles = [obstacle_1, obstacle_2]
print(obstacles)

params = example.Params()
obstacle_process = example.ObstacleProcess(params)
obstacles = obstacle_process(obstacles)
print(obstacles)

第一个打印返回:

[<example.Obstacle object at 0x7fb65271e1b0>, <example.Obstacle at 0x7fb652735070>]
,而第二个打印返回:
[<example.Obstacle at 0x7fb652734670>, <example.Obstacle object at 0x7fb652735230>]

这不是所需的输出,因为

obstacle_1
最初位于
0x7fb65271e1b0
,在
operator()
/
__call__
调用后,它位于
0x7fb652734670
。我希望
obstacle_1
保留其初始地址
0x7fb65271e1b0
,即使在另一个类 (
ObstacleProcess
) 处理完
obstacle_1
后也是如此。

以下代码为与pybind11绑定的源码:

// pybind11 binding
py::class_<Obstacle, std::shared_ptr<Obstacle>>(m, "Obstacle")
    .def(py::init<>());

py::class_<ObstacleProcess>(m, "ObstacleProcess")
    .def(py::init<
        const Params&>()
    )
    .def("__call__", &ObstacleProcess::operator_py<Params>, py::return_value_policy::reference);

下一个块展示了

operator_py
是如何在源代码中实现的:

template <Params>
std::vector<Obstacle>& operator_py(
    std::vector<Obstacle>& obstacles,
    const Params &parameters
)
{

    ...

    return obstacles
}

我尝试过有或没有

std::shared_ptr<Obstacle>
。当前的实现给出了与根本不使用
shared_ptr
相同的结果,因此我实现
shared_ptr
的方式有问题。我尝试过使用
PYBIND11_MAKE_OPAQUE(std::shared_ptr<std::vector<Obstacle>>);
,但我的实现并没有改变结果。

我没有尝试过使用

pybind11 — smart_holder branch
,也许这个分支必须用于这种情况?

python c++ memory-management c++20 pybind11
1个回答
0
投票

感谢 @DanMašek 和 @n.m.willseey'allonReddit 的评论,我们发现对

operator_py()
进行这些更改可以修复问题中的问题:

template <class Params>
std::vector<std::shared_ptr<Obstacle>> operator_py(
    std::vector<std::shared_ptr<Obstacle>> &obstacle_ptrs,
    const Params &params
)
    {
        std::vector<Tracked_Obstacle> obstacles;

        for (const auto& obstacle_ptr_0 : obstacle_ptrs)
        {
            if (obstacle_ptr_0)
                {
                    obstacles.push_back(*obstacle_ptr_0);
                }
                else
                {
                    std::cout<<"nlptr"<<std::endl;
                }
                
        }
        for (const auto& obstacle_ptr : obstacle_ptrs)
        {
            Tracked_Obstacle& obstacle = *obstacle_ptr;
            
            // do processing ...
        };
    return obstacle_ptrs;

通过此实现,获得了所需的输出:

import example

obstacle_1 = example.Obstacle()
obstacle_2 = example.Obstacle()

obstacles = [obstacle_1, obstacle_2]
print(obstacles)

params = example.Params()
obstacle_process = example.ObstacleProcess(params)
obstacles = obstacle_process(obstacles)
print(obstacles)

# output:
[<example.Obstacle object at 0x7f709bdc2430>, <example.Obstacle object at 0x7f709b12a830>]
[<example.Obstacle object at 0x7f709bdc2430>, <example.Obstacle object at 0x7f709b12a830>]
© www.soinside.com 2019 - 2024. All rights reserved.