[BUG]: __getattr__ and base class order
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
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
In the binding code below __getattr__ will only be found in the derived class if we do:
py::class_<Derived, Base, OtherBase>(m, "Derived")
if we instead do:
py::class_<Derived, OtherBase, Base>(m, "Derived")
note the order of the base classes switched,
the bound __getattr__ will never be called.
From what I understand from the documentation (https://pybind11.readthedocs.io/en/latest/advanced/classes.html#multiple-inheritance) the order of the base classes should not matter?
This is tested with the latest master as of writing.
Reproducible example code
// binding code
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Base {
virtual ~Base() = default;
int base() const { return 0; }
};
struct OtherBase {
int other() const { return 3; }
};
struct Derived : Base, OtherBase{
int id() const { return 2; }
};
PYBIND11_MODULE(bar, m) {
py::class_<Base>(m, "Base")
.def(py::init<>())
.def("base", &Base::base)
.def("__getattr__", [](Base&, std::string key) {
return "Base GetAttr: " + key;
});
py::class_<OtherBase>(m, "OtherBase")
.def("other", &OtherBase::other);
py::class_<Derived, OtherBase, Base>(m, "Derived")
.def(py::init<>())
.def("id", &Derived::id);
}
// test code
import bar
d = bar.Derived()
print(f"d.base(): {d.base()}")
print(f"d.other(): {d.other()}")
print(f"d.id(): {d.id()}")
print(f"d.prop: {d.prop}") # this will fail (if Base is not the first base class)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the provided C++ binding and Python reproduction, and read the linked pybind11 multiple-inheritance documentation first. Confirm behavior for both base-class orders and trace the relevant class-binding and attribute-lookup entry point; done means getattr behaves consistently regardless of base order, with regression coverage for the reproduction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100