If I had but one design pattern I would just LOVE to see disappear from Python, it's the need for super(). Don't get me wrong, super() is a clever piece of engineering, but if your code actually needs what it's useful for (C3 linearization, MRO, etc), then you've made things too complicated. I deplore the proliferation of libraries that have embraced the seductive, but ultimately deceptive ways of the mixin, because they saw all the big boys reaching for it. The devil gave multiple inheritance a cooler name, some new outfits, and sunglasses to confuse the Pythonistas and they embraced it with open arms.
Refactor to favor composition over inheritance. But if you really must inherit, single over multiple, and shallow over deep. Eventually your code will less and less need super() and it'll become pointless to use it over the more explicit mechanism, which incidentally makes everything cognitively lighter.
Completely agreed. The codebase I work on really badly abused multiple inheritance all over the place. Some of our classes are 5+ layers of inheritance deep.
All the code I've written since joining has used `typing.Protocol` over ABCs, simple dependency injection (i.e., no DI framework), no inheritance anywhere, and of course extensive type annotations... and our average test coverage has gone from around 6% to around 45%.
It's honestly baffling to see how insanely over-complicated most of the Python is that I see out in the wild, especially when you consider that like 90% of the apps out there are just CRUD apps.
Isn't super() also commonly used in languages that have only single inheritance?
If the language is limited to only single and shallow inheritance, then super() becomes a syntactic convenience that saves everyone the burden of spelling out the inheriting class. But in Python, even if your code emulates these constraints, you lose in clarity from using super() because someone reading your source has to wonder if or why it was specifically needed, since its main purpose is to resolve the kinds of conflicts that arise in complex inheritance scenarios (diamond, problematic cycles, and such). So, to need it is to make your code complicated. To not need it while using it, is to lose in clarity.