classification
Title: super() documentation isn't very clear
Type: Stage: patch review
Components: Documentation Versions: Python 3.6, Python 3.5, Python 3.4, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: Malcolm Smith, Tapani Kiiskinen, csabella, docs@python, martin.panter, r.david.murray, rhettinger
Priority: normal Keywords: patch

Created on 2015-03-15 19:40 by Tapani Kiiskinen, last changed 2017-07-14 17:53 by Malcolm Smith.

Files
File name Uploaded Description Edit
super.patch martin.panter, 2015-12-06 06:12 review
Messages (12)
msg238157 - (view) Author: Tapani Kiiskinen (Tapani Kiiskinen) Date: 2015-03-15 19:40
https://docs.python.org/3/library/functions.html#super

There's no mention in the document which __mro__ is used in the case of a super(Type, obj) call. There's this mention 'The __mro__ attribute of the *type* lists the method resolution search order used by both getattr() and super().' but my understanding is that this only applies in the case of a super(type) call plus it doesn't state that it only applies in that case. (I'm fairly certain I'm not wrong; if only the __mro__ of the type was used then cooperative multiple inheritance (which is referenced three paragraphs down) could not work because the __mro__ of the type never has sibling types.)

Isn't this misleading due to a super(Type, obj) call (or just super() inside a class in 3k) being the more normal way to use the function? Even now I can't find a single resource to confirm which exact mro is used in the case of a super(Type, obj) call, I've only been able to deduce that it probably uses the type(obj).__mro__ then finds the Type and then tries the entries after Type.

Finally 'If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).'

I'm interpreting this is essentially saying that if the second argument is given that the returned object will be bound, given an object the super call would return a bound instance method and given a type a bound class method? I feel like stating this explicitly would be more clear than implicitly.
msg238159 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-03-15 21:34
> There's this mention 'The __mro__ attribute of the *type* lists
> the method resolution search order used by both getattr() and super().

I think instead of *type* it should say *object-or-type*.  It is the "second argument" that supplied the MRO.  The "first arguments" determines where we are currently in that MRO so that the search can begin upstream from the current class.
msg238162 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-03-15 21:55
I agree with Tapani; what you just explained should be made explicit ("the type is skipped" isn't the same as "searching starts from the item after the type in the object's MRO").  Also, the docs imply by the phrasing that the getattr docs will explain the method resolution order, but those docs do not in fact address the topic.  Perhaps there should be a link to 'method resolution order' in the glossary?
msg238196 - (view) Author: Tapani Kiiskinen (Tapani Kiiskinen) Date: 2015-03-16 12:06
A link to the to the glossary would also be good yes. I was figuring out how super() works and as you said the doc gave the impression getattr would explain more but it doesn't. Had to use google to find the glossary entry for MRO which had the link explaining how that is calculated.
msg255685 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-12-02 00:52
Here are some specific changes I suggest:

1. Most confusing: super() uses the MRO of the second argument, not the first.

2. Clarify that is is not just the first argument that is skipped in the MRO, it is all preceding classes as well. The first argument does not have to be the class at the start of the MRO.

3. Revise signature and use consistent parameter names in text. Currently, “obj” and “type2” are only defined in the doc string. Perhaps super(subclass[, self]). Or maybe super(type[, obj]), matching error messages, or super(thisclass[, self]), matching the special attributes. Type and type2 are too confusing for my taste.

4. Link to the glossary rather than getattr().

5. Explain more about unbound super objects, when the second argument is omitted. Apparently they are descriptors; when you set them on a class and then “get” them in an instance, you get a new version bound to that instance. This is obscure, but I feel it might help the general understanding. [It seems you cannot bind a super() object to a class this way; maybe that is a bug.]

6. Explain more about “bound” super objects: getting a method from the super object binds the method to the second argument. [This also works for getting data properties, but not setting or deleting them; see Issue 14965.]

7. Not only isinstance() or issubclass() must be satisfied, but the first argument must be a concrete class. Virtual subclassing is not sufficient if the subclass is not in the MRO. This would address Issue 20503. Also, the first argument should be a derived class, not “object” itself.
msg256004 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-12-06 06:12
Here is a patch against Python 3 with my suggestions. Let me know what you think, if I got anything wrong, extra bits that could be changed, etc.
msg291348 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2017-04-09 00:16
The magical no-argument call could also be clarified:

8. Define in the main text what happens when you omit the first argument (the subclass) to “super”. At the moment, I think the reader could infer that it is the method’s class, but this is only hinted by reading the comment in the illustration and Raymond’s external web page. The documentation should also clarify how it works, or at least be clear when it is not supported (e.g. one method assigned to multiple classes, functions defined outside a class definition, decorators that re-create the class, “super” renamed).

9. The no-argument call creates an instance bound to the first argument of the method, not an unbound instance. Determining the “self” argument is also magical: it does not seem to work with default arguments, variable positional arguments, nor keyword-only arguments. List comprehensions, generator expressions, etc seem to override it, and the argument is not seen by exec and eval.
msg293986 - (view) Author: Cheryl Sabella (csabella) * Date: 2017-05-19 23:51
I don't know if it's appropriate to add this to this ticket, but on the Data Model doc page, section 3.3.2.2 for Invoking Descriptors describes Super Binding.  A separate discussion with Nick in PR 1561 highlighted that section as a possible candidate for clarification.  It seemed to fit in with the discussion of super() and __mro__ here.
msg294012 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-05-20 06:48
Martin, can we just fix the signature here.  It is not the purpose of the super docs explain the MRO (that is a feature of all new-style classes, super() is just something that hops to the next in the chain) or to be a tutorial.  I would like to keep the rest of the docs mostly as-is.  These docs have already been refined multiple times and proven themselves usable for a lot of user).   The only part that wasn't previously edited was the parameter names for the signature.
msg294026 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2017-05-20 10:32
Cheryl: see also Issue 25777 and Issue 20751, both about the “super binding” under Invoking Descriptors.

Raymond: if you want to just pick parts of my patch, go for it. But I don’t understand your concern about explaining the MRO. I think it is important to explain which base classes are skipped, and which are searched. It is not just the type/subclass (super.__thisclass__) entry in the MRO that is skipped; this parameter determines the starting point, so the preceding entries are also skipped.

Another problem with referring to “getattr” is that it checks for instance attributes and custom __getattr__ and __getattribute__ implementations, but I don’t think “super” does any of that.

Looking at my patch now, I would propose that the exception message only be changed in the current (3.7) branch.
msg294042 - (view) Author: Cheryl Sabella (csabella) * Date: 2017-05-20 18:08
Thank you for pointing out those other links.  For me, they all tie together because I was originally trying to figure out why the data model page defined `super(B, obj).m()` instead of just `super().m()`.  It seems that the zero argument super is preferred, so I was trying to understand when to use the other form.  I didn't intend to question whether the docs needed to be rewritten.
msg298365 - (view) Author: Malcolm Smith (Malcolm Smith) Date: 2017-07-14 17:53
I agree that the first two paragraphs are confusing. It's clearly not true to say "The search order is same as that used by getattr() except that the type itself is skipped", because as noted above, everything *earlier* than the type in the MRO is also skipped. The second paragraph then goes on to imply that super() uses the MRO of its first argument, which contradicts the first paragraph, and apparently isn't true either.

Raymond explained the actual behavior quite clearly in his comment of 2015-03-15 21:34, and that's what the documentation should do as well.
History
Date User Action Args
2017-07-14 17:53:05Malcolm Smithsetnosy: + Malcolm Smith
messages: + msg298365
2017-05-20 18:08:56csabellasetmessages: + msg294042
2017-05-20 10:32:19martin.pantersetmessages: + msg294026
2017-05-20 06:48:50rhettingersetmessages: + msg294012
2017-05-19 23:51:37csabellasetnosy: + csabella
messages: + msg293986
2017-04-09 00:16:35martin.pantersetmessages: + msg291348
2015-12-06 06:12:15martin.pantersetfiles: + super.patch
keywords: + patch
messages: + msg256004

stage: patch review
2015-12-02 01:02:16martin.panterlinkissue20503 dependencies
2015-12-02 00:52:56martin.pantersetmessages: + msg255685
versions: - Python 3.2, Python 3.3
2015-12-01 09:54:47martin.panterlinkissue25772 superseder
2015-03-21 02:50:50martin.pantersetnosy: + martin.panter
2015-03-16 12:06:01Tapani Kiiskinensetmessages: + msg238196
2015-03-15 21:55:48r.david.murraysetnosy: + r.david.murray
messages: + msg238162
2015-03-15 21:34:03rhettingersetmessages: + msg238159
2015-03-15 21:06:39rhettingersetassignee: docs@python -> rhettinger

nosy: + rhettinger
2015-03-15 19:40:51Tapani Kiiskinencreate