Emile D.
Emile D.

Reputation: 642

Pybind11: init<> with lambda

I use pybind11 as a wrapper of my C++ code into a python library.

It happens that there are arguments that I can't provide or sometimes I want to do a conversion/initialization that I know in the C++ side. It could be because the class is not known in python, for instance. How could that be done? The only "solution" I see so far would be to create an inherited proxy class in C++.

Example: I want to define/bind a python class A:

class A:
  def __init__(self, B b):
    ...

With a C++ equivalent class:

class A {
  A(C c, D d);
}

Is there some kind of lambda or an equivalent that I could create for the pybind11::init<>?

Upvotes: 9

Views: 7741

Answers (1)

Jesse C
Jesse C

Reputation: 839

pybind11 lets you bind factory functions as init methods. So you would have to provide a function in c++ that took a B and return an A and then you could bind that as an init method for A.

An example from the pybind11 docs

class Example {
private:
    Example(int); // private constructor
public:
    // Factory function:
    static Example create(int a) { return Example(a); }
};

py::class_<Example>(m, "Example")
    .def(py::init(&Example::create));

You should be able to bind in a free function as well (not just a static function), if you do not want to (or can't) change class A in c++.

So it could look something like this (changed to return a unique_ptr, which pybind can just take ownership of vs a raw instance. But either should work)

std::unique_ptr<A> createA(const B& arg)
{
  // returns an instance of A that you made using B
}

py::class_<A>(m, "A")
    .def(py::init(&createA));

You obviously then have to also provide a binding for B in python.

Docs are here and include even more examples, including how to do an init lambda as well: https://pybind11.readthedocs.io/en/stable/advanced/classes.html#custom-constructors

Upvotes: 10

Related Questions