On Sat, Mar 26, 2022 at 10:40:45AM -0700, Christopher Barker wrote:
Almost -- I think super() acts a proxy to the *perents*, plural.
Correct. In general, classes do not have a parent. They have one or more parents, each of which in turn can have one or more parents. Anyone talking about the "parent" or "base class" of a generic, unspecified Python class is stuck in a single inheritance world. Years ago, James Knight wrote a provocatively titled blog post called "super considered harmful". https://fuhm.net/super-harmful/ After much discussion on one of the Python lists, I think it was Python-Dev, he backed down somewhat and admitted that actually yes, super is great, "but you can't use it." Except of course thousands of people do use it. And it works.
If you just want the superclass, you can call it directly:
class B(A): def some_method(self, ...): A.some_method(self)
Please please please don't do that! That just needlessly breaks multiple inheritance, and for no good purpose. Just use super(), even for single inheritance. Anyone who hasn't read Raymond Hettinger's "super considered super", please do. https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
The point of super() is to provide a way to, yes, implicitly, call a method on all the superclasses in the inheritance tree.
No, it is not implicit. Please don't repeat that mistake. `super().some_method(self)` is perfectly explicit. It is just that the specific class used is computed at runtime, not hard-coded. We wouldn't say that get_parent().some_method(self) is "implicit" because the parent is computed at runtime. We should stop saying that super() is "implicit". It is not. It is an explicit call to resolve the mro and call some_method on the appropriate parent. The only "implicit" part of super is that it implicitly knows the current context. But that's not a point against it. Nobody complains that functions "implicitly" know their global environment, and therefore name resolution in functions is broken due to implicitness: # thismodule.py def func(): return "something" def main(): return func() # Oh no, it is "implicit"! # should write: return thismodule.func() # Much more explicit!!! Despite what the Zen says, sometimes a modicum of implicit knowledge is worth an imperial ton of explicit verbosity. And the zero-argument form of super() is one of those times.
There's more than one way to do that, but it's perfectly reasonable that Python provide only one way, with clear rules, which is what we have now. And if there's going to be one way, the MRO currently in use is a pretty darn good one.
The C3 linearization used by Python is provably correct. I am not aware of any other non-broken linearization algorithms for multiple inheritance. Perhaps they exist; perhaps not. Before we had C3, the ways multiple inheritance was resolved in Python 1.x through 2.2 was broken. Note carefully that we had **two** ways of resolving multiple inheritance, for classic classes and new-style classes, and both were broken in different ways, until we moved to a proven algorithm in Python 2.3. https://www.python.org/download/releases/2.3/mro/ -- Steve