pybind / pybind/pybind11

Pass a reference to C++ container to the Python callback

Open
#1,200 5 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Hi!

I faced this issue while implementing a Python's os.walk-like function for my tree structure. I hoped to mimic the ability of callback to edit passed list of directories in-place and guide further search.

Suppose we have the following in C++:

#include <pybind11/stl_bind.h>

PYBIND11_MAKE_OPAQUE(std::vector<double>);
namespace py = pybind11;
...

py::bind_vector<std::vector<double>>(m, "d_list", py::module_local(false));
// this will work as expected because I can explicitly point that return value is a reference
m.def("test_static_d", []() -> std::vector<double>& {
	static std::vector<double> v{0, 0};
	return v;
}, py::return_value_policy::reference);

// callback will fail to edit passed vector, because a copy is involved somewhere?
m.def("test_callback", [](std::function<void(std::vector<double>&)> f) {
	std::vector<double> v{0, 0};
	f(v);
	for(const auto& l : v) {
		std::cout << l << ' ';
	}
	std::cout << std::endl;
});

And now the Python code:

In [2]: a = example.test_static_d()

In [3]: a.append(1)

In [4]: a
Out[4]: d_list[0, 0, 1]

In [5]: b = example.test_static_d()

In [6]: b
Out[6]: d_list[0, 0, 1]
# so far so good
In [7]: b is a
Out[7]: True

# callback seems to modify a copy of vector
def f(v) :
    v.append(1.)
    print(v)

# C++ function don't get updated vector after callback invoke
In [1]: example.test_callback(f)
d_list[0, 0, 1]
0 0 

Is there a way to specify that callback should take an opaque container by reference (in order to modify it in-place on Python side)?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the contrast between test_static_d and test_callback using the opaque std::vector binding from pybind11/stl_bind.h. Trace how the std::function callback argument is converted, then verify that mutations made by the Python callback are visible in the C++ vector after the callback returns.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.