I think multiple inheritance will always scare me. What order do the superclass inits run in? What happens if they do conflicting things? What if some superclasses call super().__init__ and others don't?
No thanks, I'll suffer through reading a few additional lines of:
def __init__(self, \*kwargs):
# What does this do? No one knows
super().__init__(self, \*kwargs)
def calculate(self):
source = self.get_source()
return self.get_stuff(source)
Meh, that's just the standard composition vs inheritance dichotomy. In reality, those two concepts are orthogonal, and you can use one, the other, and both, as suitable to the situation.
Using multiple inheritance to implement certain common functionality, using mixin classes, is possible in Python; it's another powerful tool in the arsenal, but doesn't mean that you have to use it.
Inheritance works best to denote "is-a" relationships, i.e. for defining subtypes, especially when using type annotations and checks. Sometimes - albeit very rarely - you need a class that belongs to two separate type hierarchies; multiple inheritance comes very handy in those cases.
I don't think he is unaware of any of that. His point was that multiple inheritance involves enough fiddly surprising behaviour that it's best avoided - you are better off manually delegating to distinct member variables, then it is clear what is happening even if it is a bit more tedious.
(Btw that's the only way to implement inheritance in Rust, even single inheritance.)
The Method Resolution Order (MRO) is firm and documented. It's just not something anyone keeps in mind unless you use multiple inheritance a lot.
Conflicts are determined by the MRO. If some classes don't call super(), then they won't call super --> classes further down the MRO won't be called and won't be initialized.
The choice isn't: multiple inheritance or a couple lines. In the right situation, multiple inheritance could save hundreds of lines and condense a complicated mechanism into a simplistic one. Used flippantly, they can be a nightmare -- but that's true of all programming paradigms.
Agree, core feature of Python is to be readable and familiar. While I enjoy reading more advanced deep dives in language features, at the point you’re being crafty to flex, it’s likely bad idea; aka if next person reading your code mostly will have no clue what it’s doing, it’s likely a bad idea to do.
Wish there was a way to visualize or rate how average code is - especially two separate versions covering same concept; hence my other comments on resources to quantify usage patterns.
Over thinking it, I think this is probably the "right" solution to multiple inheritance where there are conflicting attributes.
I suspect it is a hard pre-commit check but you would want to only inherit from classes with no conflict- then if there are it is down to this approach (!)
No thanks, I'll suffer through reading a few additional lines of:
class SomeBusinessyThing:
vsclass SomeBusinessyThing(Utils, Other):