How to make a Python callback funtion match (i.e. become compatible with) a pybind11 C++ class constructor signature? #5996
Unanswered
TrondMelen
asked this question in
Q&A
Replies: 2 comments
-
|
You are better of using std::function since it is natively supported by pybind11. with small change i have below working example , i have added inline comments as well. Also,I have just clubbed to one cpp file for simplicity #include <pybind11/pybind11.h>
namespace py = pybind11;
#include <pybind11/functional.h>
// a struct
struct data_s {
unsigned int sequence_counter;
unsigned int byte_count;
unsigned char array[100];
};
Python
// class with a constructor and one method/function
class My_class {
public:
My_class(std::function<void *(const struct data_s &)> data_handler) :
the_data_handler(data_handler) {}
void run() {
data_s data; // struct allocation
(the_data_handler)(data); // the callback is executed here
}
private:
// use std::function since it will be natively supported
std::function<void *(const struct data_s &)> the_data_handler; // the callback is stored here
};
PYBIND11_MODULE(my_module, m, py::mod_gil_not_used()) {
// need to expose the data_s struct in python else python will not know when accessing its elements
py::class_<data_s>(m, "data_s")
.def(py::init<>())
.def_readwrite("sequence_counter", &data_s::sequence_counter)
.def_readwrite("byte_count", &data_s::byte_count);
// in case array[100] is needed its not natively supported you will need to use py::array wrapper
// best would be to use std::vector
py::class_<My_class>(m, "My_class")
.def(py::init<std::function<void *(const struct data_s &)>>())
.def("run", &My_class::run);
}import my_module as mym
class data_s:
def __init__(self):
self.sequence_counter = 0
self.byte_count = 0
# To access array[100] you will need to to use py::array and write a procedure for it
def my_data_handler(data: data_s):
# below print will print garbage value for data.sequence_counter since its not initialized in cpp
print(f"my_data_handler(): counter is {data.sequence_counter}\n")
api=mym.My_class(my_data_handler)
api.run() |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Thank you very much Murthy L,
for taking the time to look into the problem, and for suggesting a solution. This looks very promising!
Best regards,
Trond
***@***.***?anonymous&ismsaljsauthenabled&ep=owaSlotsEmailSignature>
Book time to meet with ***@***.***?anonymous&ismsaljsauthenabled&ep=owaSlotsEmailSignature>
…________________________________
Fra: Murthy L ***@***.***>
Sendt: tirsdag 10. mars 2026 10:58
Til: pybind/pybind11 ***@***.***>
Kopi: Trond Melen ***@***.***>; Author ***@***.***>
Emne: Re: [pybind/pybind11] How to make a Python callback funtion match (i.e. become compatible with) a pybind11 C++ class constructor signature? (Discussion #5996)
You are better of using std::function since it is natively supported by pybind11.
Also you will need to expose data_s to python via pybind11 else you will not be able to access elements
with small change i have below working example , i have added inline comments as well. Also,I have just clubbed to one cpp file for simplicity
#include <pybind11/pybind11.h>
namespace py = pybind11;
#include <pybind11/functional.h>
// a struct
struct data_s {
unsigned int sequence_counter;
unsigned int byte_count;
unsigned char array[100];
};
Python
// class with a constructor and one method/function
class My_class {
public:
My_class(std::function<void *(const struct data_s &)> data_handler) :
the_data_handler(data_handler) {}
void run() {
data_s data; // struct allocation
(the_data_handler)(data); // the callback is executed here
}
private:
// use std::function since it will be natively supported
std::function<void *(const struct data_s &)> the_data_handler; // the callback is stored here
};
PYBIND11_MODULE(my_module, m, py::mod_gil_not_used()) {
// need to expose the data_s struct in python else python will not know when accessing its elements
py::class_<data_s>(m, "data_s")
.def(py::init<>())
.def_readwrite("sequence_counter", &data_s::sequence_counter)
.def_readwrite("byte_count", &data_s::byte_count);
// in case array[100] is needed its not natively supported you will need to use py::array wrapper
// best would be to use std::vector
py::class_<My_class>(m, "My_class")
.def(py::init<std::function<void *(const struct data_s &)>>())
.def("run", &My_class::run);
}
import my_module as mym
class data_s:
def __init__(self):
self.sequence_counter = 0
self.byte_count = 0
# To access array[100] you will need to to use py::array and write a procedure for it
def my_data_handler(data: data_s):
# below print will print garbage value for data.sequence_counter since its not initialized in cpp
print(f"my_data_handler(): counter is {data.sequence_counter}\n")
api=mym.My_class(my_data_handler)
api.run()
—
Reply to this email directly, view it on GitHub<#5996 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/B3XEY722UYLZPBXTCKHXJ534P7ROHAVCNFSM6AAAAACWAPN3OWVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTMMBWGYZDKNY>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I try to make a Python interface to an existing API represented by a C++ class where internal events trigger the execution of registered callbacks. I would be grateful if someone can help. Thanks in advance!
The simplified case below demonstrates my problem. The C++ 'My_class' constructor expects one argument of type '(void (data_s const&))', but to Python this is incompatible with '<function my_data_handler at 0x7fef4d1fc180>'. The class instantiation fails with the Python error message "
TypeError: __init__(): incompatible constructor arguments." I guess I must either relax the C++ type or tighten the Python type. Right?The C++ file 'My_class.hpp' defining (header only) 'My_class':
The pybind11 C++ file 'binder.cpp':
The Python program 'main.py' that fails:
The failing interactive Python session:
Pybind11 is version 2.13.6
Beta Was this translation helpful? Give feedback.
All reactions