-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
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 to Foo(...).
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 a pybind11::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
| chain = (detail::function_record *) rec_capsule; |
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 call pybind11_fail without calling PyErr_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