-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG]: Overriding __new__ (or type-level __call__) for a pybind11 class should be supported #3253
Comments
PR welcome on this front. I think there are also some open issues that show hacks to define metaclasses with PyBind, so we could support if there is demand. Also please feel free to send a PR to fix the bug pointer methods for the PyCapsule. |
|
So solving the sibling bug was pretty trivial, the bigger issue though is that new is not respected on our |
Closed by #3265 |
With #3265 we can safely define a Singleton: struct Singleton {
static Singleton *get_instance() {
static auto ptr = new Singleton();
return ptr;
}
private:
Singleton() {
print_created(this, "via get_instance");
}
Singleton(const Singleton &) = delete;
Singleton(Singleton &&) = delete;
~Singleton() { print_destroyed(this); }
};
py::class_<Singleton, std::unique_ptr<Singleton, py::nodelete>>(m, "Singleton")
.def(py::init([]() { return nullptr; }))
.def_static("__new__",
[](const py::object &) { return Singleton::get_instance(); }); In python, this runs smoothly a = Singleton()
b = Singleton()
assert a is b Meanwhile, there is a slight issue: When I add py::class_<Singleton, std::unique_ptr<Singleton, py::nodelete>>(m, "Singleton")
.def(py::init([]() { return nullptr; }))
// this would not help either:
// .def(py::init([]() { return nullptr; }), py::return_value_policy::reference_internal)
.def_static("__new__",
[](const py::object &) { return Singleton::get_instance(); },
py::return_value_policy::reference_internal); In [2]: a = m.Singleton()
### test_submodule_class_(module_&)::Singleton @ 0x564a28ebc150 created via get_instance
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[2], line 1
----> 1 a = m.Singleton()
TypeError: pybind11_tests.class_.Singleton.__init__() must be called when overriding __init__ |
Required prerequisites
Problem description
It would be nice if, for a given pybind11-defined class
Foo
, there were a mechanism for overriding the object returned by a call toFoo(...)
.In Python, this can be done by overriding
__new__
or by using a custom metaclass with an overridden__call__
method:https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
One case where this would be useful is to be able to return a reference to an existing object. Currently, even if we use
std::shared_ptr
as the holder type and return a reference to an existing object from apybind11::init
function, we will end up with a new Python object, which is unfortunate.As far as I am aware, that problem is impossible to remedy from
__init__
, since by the time__init__
is called, the Python object has already been created. Instead, we must either use__new__
or the metaclass__call__
.Currently, pybind11 does not support defining
__new__
. Attempting to define a method named"__new__"
results in an error due to this line:pybind11/include/pybind11/pybind11.h
Line 420 in 6abf2ba
The sibling (the existing
__new__
function) is not a PyCapsule, which causes this to fail. Incidentally,pybind11::capsule::{get,set}_pointer
have a bug, in that they callpybind11_fail
without callingPyErr_Clear()
, which leads to an assertion failure elsewhere due to an unexpected error indicator state.I suspect that it may take a decent amount of work beyond addressing this immediate error to make
__new__
work, though.An alternative workaround is to define a metaclass. That works, but is non-trivial since pybind11 itself provides no support for defining metaclasses, and you must take care to inherit from pybind11's own metaclass.
Reproducible example code
No response
The text was updated successfully, but these errors were encountered: