[issue23674] super() documentation isn't very clear
New submission from Tapani Kiiskinen: 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. ---------- assignee: docs@python components: Documentation messages: 238157 nosy: Tapani Kiiskinen, docs@python priority: normal severity: normal status: open title: super() documentation isn't very clear versions: Python 2.7, Python 3.2, Python 3.3, Python 3.4, Python 3.5, Python 3.6 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Changes by Raymond Hettinger <raymond.hettinger@gmail.com>: ---------- assignee: docs@python -> rhettinger nosy: +rhettinger _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Raymond Hettinger added the comment:
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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
R. David Murray added the comment: 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? ---------- nosy: +r.david.murray _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Tapani Kiiskinen added the comment: 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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Changes by Martin Panter <vadmium+py@gmail.com>: ---------- nosy: +vadmium _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Martin Panter added the comment: 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. ---------- versions: -Python 3.2, Python 3.3 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Martin Panter added the comment: 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. ---------- keywords: +patch stage: -> patch review Added file: http://bugs.python.org/file41255/super.patch _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Martin Panter added the comment: 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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Cheryl Sabella added the comment: 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. ---------- nosy: +csabella _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Raymond Hettinger added the comment: 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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Martin Panter added the comment: 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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Cheryl Sabella added the comment: 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. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Malcolm Smith added the comment: 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. ---------- nosy: +Malcolm Smith _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue23674> _______________________________________
Change by Raymond Hettinger <raymond.hettinger@gmail.com>: ---------- pull_requests: +15239 pull_request: https://github.com/python/cpython/pull/15564 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment: New changeset cd81f0500fe98c7f4cddb06530fffabd14f036b8 by Raymond Hettinger in branch 'master': bpo-23674: Clarify ambiguities in super() docs (#15564) https://github.com/python/cpython/commit/cd81f0500fe98c7f4cddb06530fffabd14f... ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>: ---------- pull_requests: +15261 pull_request: https://github.com/python/cpython/pull/15585 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>: ---------- pull_requests: +15262 pull_request: https://github.com/python/cpython/pull/15586 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
Change by Raymond Hettinger <raymond.hettinger@gmail.com>: ---------- resolution: -> fixed stage: patch review -> resolved status: open -> closed _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment: New changeset 43b7ed77a8224c378b436ad3385733454198be41 by Raymond Hettinger (Miss Islington (bot)) in branch '3.8': bpo-23674: Clarify ambiguities in super() docs (GH-15564) (GH-15586) https://github.com/python/cpython/commit/43b7ed77a8224c378b436ad338573345419... ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue23674> _______________________________________
participants (7)
-
Cheryl Sabella
-
Malcolm Smith
-
Martin Panter
-
miss-islington
-
R. David Murray
-
Raymond Hettinger
-
Tapani Kiiskinen