fluctuation
fluctuation

Reputation: 55

How can I save a python function to a static c++ container using pybind11?

Essentially, on the C++ side I have a container that holds a certain type of function. Now I would like to expose this container to python with the possibility for the users to provide their own python functions.

The simplest example would look like this:

#include "pybind/common/Common.h"
using CppFunc = std::function< int (int) >;
PYBIND11_MODULE( test, m )
{
    m.def("addFunc", [](const pybind11::function& f){
    static std::vector<CppFunc> vec{};
    vec.push_back(f.cast<CppFunc>());
    });
}

Then in python I would like to just do something like this.

import test

def myFunc(number):
    return number+1

test.addFunc(myFunc)

Interestingly enough, this works fine. However, if I run the script with "python script.py" it runs through and then never terminates. In an interactive console, the same code works fine until you try to close the console: the process gets stuck.

How can I safely store this python function in the C++ container?

Upvotes: 2

Views: 530

Answers (1)

Sergei
Sergei

Reputation: 1799

static std::vector<CppFunc> vec{} stores references to python objects (user functions) which never get released due to static storage, therefore interpreter cannot terminate.

To ensure interpreter termination you can call a cleanup function at module termination:

#include "pybind11/pybind11.h"
#include "pybind11/functional.h"

namespace py = pybind11;

using CppFunc = std::function< int (int) >;

PYBIND11_MODULE( test , m )
{
    static std::vector<CppFunc> vec{};

    m.def("addFunc", [](CppFunc f){
        vec.push_back(std::move(f));
    });

    m.add_object("_cleanup", py::capsule([]{ vec.clear(); }));
}

See doc for more details: https://pybind11.readthedocs.io/en/stable/advanced/misc.html#module-destructors

Upvotes: 2

Related Questions