Location:this issue page
As it's implemented in C++, pybind11 doesn't have an equivalent to Swig's %pythoncode blocks, and that means any Python code we add to wrapped classes needs to go in a regular Python file. This is straightforward to do, but verbose and a bit hard to read, especially if you want to avoid introducing unnecessary symbols:
We had a brief and anticonvergent discussion about how to make this work better in the #dm-pybind11-porting Slack channel a few days ago, and I've since taken a bit of time to explore the options and come up with my own preferred proposal.
I propose we add a class decorator that effectively re-opens wrapped classes, allowing us to add new methods to them using the usual Python class definition syntax:
I'll admit the implementation of this decorator is going to be a bit tricky: it can't actually reopen the class definition, so it actually iterates over the decorated class's attributes and adds them to the existing class with the same name, while making sure not to copy special attributes that are added implicitly to all classes (e.g. __module__). But that implementation is still at most about 10 lines of code in a module most devs will never have to touch, and I think the benefits are quite obvious: a large fraction of our wrapper code will be vastly more readable.
The big downside of this decorator is that it doesn't allow the type to be extended to be computed. That's primarily a problem with wrappers for C++ template instantiations, however, and I have a different proposal for how to add Python extensions (among other things) to those on
DM-8805. For other cases, I think we should also add a function decorator that would allow the following syntax:
This is just as compact as the class decorator when only a single attribute is added, and it's quite simple to implement. But the readability is much worse when multiple attributes are involved: there's no common indentation block, and the class name is repeated and is much less prominent. Like the decorator-free approach, it also adds unwanted module-level symbols as side effect, though these can be ignored by using __all__ in most contexts we'd use the decorator.
I'd rather not have a different policy just for adding single attributes; we'll all too often want to add additional attributes and have to reformat what was done before. So I think our pybind11 coding conventions should suggest the function decorator be used only in the (rare) cases where the class decorator would not work because the to-be-extended type must be computed and it is not a wrapped template class suitable for the