How to wrap a singleton class using pybind11?

你。 提交于 2019-12-24 05:00:14

问题


I have a singleton class in C++ (no public constructor, C++ programmers call class.instance() to create the singleton or return the existing one).

I'd prefer to hide this at the Python level. If I was writing a Python singleton, I'd handle that in __new__. If a class has no public constructor I don't think I can create an __init__ wrapper (my attempts at that have failed). I saw no mention of __new__ in the pybind11 docs (though might have missed it, and Google seems happy to elide underscores an return pages containing "new", with no mention of __new__).

Is there a singleton recipe for pybind11 (or even Boost.Python)?


回答1:


You don't need to expose __init__ if you don't instantiate your class from Python. As for your question, you can try something like this:

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



回答2:


I'm not sure about pybind11, but I believe it should be possible to wrap your class using Boost.Python. (Your question reads "or even Boost.Python"...)

Use noncopyable and/or no_init:

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

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




回答3:


assuming your singleton class looks like this:

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

You could wrap it up like so:

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

Key here is to use py::nodelete so the destructor is not referenced (and your c++ singleton is not destructed when the unique_ptrs used by multiple python instances are garbage-collected).

That code also relies on the custom constructor support introduced with pybind11 v2.2.0 (August 31st, 2017) which allows us to wrap a lambda instead of a constructor inside the init.

References
- Pybind11 v2.2.0 changelog
- Pybind11 doc about custom constructors
- Pybind11 doc on non-public destructors



来源:https://stackoverflow.com/questions/41814652/how-to-wrap-a-singleton-class-using-pybind11

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!