classification
Title: Make super() work with staticmethod by using __class__ for both arguments to super()
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: ashwch, denisr, ncoghlan, rhettinger
Priority: normal Keywords:

Created on 2017-08-04 06:42 by ashwch, last changed 2018-05-14 16:02 by denisr. This issue is now closed.

Messages (4)
msg299733 - (view) Author: Ashwini Chaudhary (ashwch) * Date: 2017-08-04 06:42
From this question I noticed that super() doesn't work with static methods with no arguments: https://stackoverflow.com/q/45498675/846892

My question is what's the issue with using __class__ for both arguments to super() in case of static method? Or was it just an oversight.
msg300594 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-08-20 03:30
Do you have a use case?  This seems doesn't seem like it would be helpful at all and would make super a little more confusing than it already is.
msg300597 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2017-08-20 05:14
Thanks for the suggestion, but I'm closing this RFE, as there are two strong arguments against it: one related to implementation feasibility, and one related to the nature of what super() *does*.

The feasibility argument is that the compiler doesn't even have the necessary information to do this, since it doesn't know what kind of method it's dealing with (it has no idea what decorators actually do, it just compiles them as subexpressions). Instead, the compiler blindly translates "super()" into "super(__class__, <first positional argument>)" when inside a function definition that's inside a class definition. As a result, there's no way for the compiler to special case static methods and pass __class__ as the second argument as well.

Even without considering that technical limitation though, using __class__ for both arguments doesn't do anything particularly sensible, since super() is specifically about resolving name lookups using the *dynamic* method resolution order (MRO) of the class the method was retrieved from (which may be a subclass of the class defining the method).

So in instance methods and class methods, type(self) or cls provides the dynamic MRO to use, while __class__ identifies *where* along that MRO the currently running method implementation sits.

In a static method, there's no dynamic MRO available for super() to query. This means that if you want access to one, you need to convert the method to a classmethod first so that the interpreter will pass in a reference to the class the method was retrieved from (as opposed to the one where it was defined, which is what __class__ gives you).

If folks actually do want to make a method implementation in a child class depend on a static method in a parent class, there are two ways to do that, but only one of them will work correctly in the face of multiple inheritance:

1. Make the child method a class method. This is the most readable approach, since you can then use zero-argument super() to call the staticmethod in the parent class in the usual way. As long as all child classes overriding the method adhere to this approach, that particular class hierarchy will also reliably respect Python's MRO linearisation rules in the case of multiple inheritance.

2. Make the child method a staticmethod, and then use "super(__class__, __class__)" to access the staticmethod in the parent class. This will work OK in cases where there aren't any diamonds in the inheritance hierarchy, but it completely bypasses the dynamic C3 linearisation algorithm, and hence may do weird things in the presence of such diamonds (i.e. cases where a subclass has multiple inheritance paths back to a given base class - see https://python-history.blogspot.com.au/2010/06/method-resolution-order.html for more detail on this).
msg316527 - (view) Author: Denis Ryzhkov (denisr) Date: 2018-05-14 16:02
Simple explanation: if you call a method of a parent, then you are using class information now, so your child method is not static any more. Please use classmethod decorator and super() with no arguments - it will use cls argument implicitly
History
Date User Action Args
2018-05-14 16:02:02denisrsetnosy: + denisr
messages: + msg316527
2017-08-20 05:14:08ncoghlansetstatus: open -> closed
resolution: rejected
messages: + msg300597

stage: resolved
2017-08-20 03:30:05rhettingersetnosy: + rhettinger
messages: + msg300594
2017-08-04 06:47:25serhiy.storchakasetnosy: + ncoghlan
2017-08-04 06:44:18ashwchsetcomponents: + Interpreter Core
2017-08-04 06:42:55ashwchcreate