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)?
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:assuming your singleton class looks like this:
You could wrap it up like so:
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
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/orno_init
:https://mail.python.org/pipermail/cplusplus-sig/2004-March/006647.html