Skip to content

[BUG]: Overriding __new__ (or type-level __call__) for a pybind11 class should be supported #3253

@jbms

Description

@jbms

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 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:

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions