Как обернуть одноэлементный класс с помощью pybind11?

У меня есть одноэлементный класс на С++ (без открытого конструктора, программисты на С++ вызывают class.instance() для создания одноэлементного или возврата существующего).

Я бы предпочел скрыть это на уровне Python. Если бы я писал синглтон Python, я бы справился с этим в __new__. Если у класса нет общедоступного конструктора, я не думаю, что смогу создать оболочку __init__ (мои попытки не увенчались успехом). Я не видел упоминания о __new__ в документах pybind11 (хотя, возможно, пропустил его, и Google, похоже, счастлив игнорировать подчеркивание страниц возврата, содержащих «новые», без упоминания __new__).

Есть ли рецепт синглтона для pybind11 (или даже Boost.Python)?


person smontanaro    schedule 23.01.2017    source источник


Ответы (3)


Вам не нужно раскрывать __init__, если вы не создаете экземпляр своего класса из Python. Что касается вашего вопроса, вы можете попробовать что-то вроде этого:

py::class_<CppSingle>(mod, "Single")
.def_static("__new__", [](py:object) { return CppSingle::instance(); )},
 py::return_value_policy::reference_internal);
person Roman Miroshnychenko    schedule 03.04.2017

предполагая, что ваш одноэлементный класс выглядит так:

class MySingleton{
    // private constructor here
public:
    MySingleton& instance();    
};

Вы можете обернуть это так:

    py::class_<MySingleton, std::unique_ptr<MySingleton, py::nodelete>>(m, "MySingleton")
    .def(py::init([](){ 
        return std::unique_ptr<MySingleton, py::nodelete>>(&MySingleton::instance());
    });

Ключевым моментом здесь является использование py::nodelete, поэтому на деструктор не ссылаются (и ваш синглтон С++ не уничтожается, когда unique_ptrs, используемые несколькими экземплярами python, удаляются сборщиком мусора).

Этот код также зависит от поддержки пользовательского конструктора, представленной в pybind11 v2.2.0 (31 августа 2017 г.), которая позволяет нам обернуть лямбду вместо конструктора внутри init.

Ссылки
 – Pybind11 v2. Журнал изменений 2.0
 – Документ Pybind11 о пользовательских конструкторах
- Документ Pybind11 по закрытым деструкторам

person gg99    schedule 29.05.2018

Я не уверен насчет pybind11, но я считаю, что ваш класс можно обернуть с помощью Boost.Python. (Ваш вопрос гласит "или даже Boost.Python"...)

Используйте noncopyable и/или no_init:

class_<Klass, boost::noncopyable>("Klass", no_init)
    .staticmethod("instance")
    ;

https://mail.python.org/pipermail/cplusplus-sig/2004-March/006647.html

person Christopher Bruns    schedule 15.03.2017