This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: `super` and descriptor clarification
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.10, Python 3.9, Python 3.8, Python 3.7, Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: Arthur-Milchior, docs@python, rhettinger
Priority: normal Keywords:

Created on 2021-12-26 15:38 by Arthur-Milchior, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (6)
msg409201 - (view) Author: Arthur Milchior (Arthur-Milchior) * Date: 2021-12-26 15:38
I find super documentation confusing because it uses multiple variables that are never introduced. Once you understand super, the meaning of those variables gets easier to understand, but still, I believe that it would help the documentation to rephrase some sentences.

In https://docs.python.org/3/reference/datamodel.html#invoking-descriptors you can read
> If a is an instance of super, then the binding super(B, obj).m() searches obj.__class__.__mro__ for the base class A immediately following B and then invokes the descriptor with the call: A.__dict__['m'].__get__(obj, obj.__class__).

It took me many reading to understand that `obj` is supposed to be a new variable; and also why `a` only appear once in the line. I believe it'd be better to explicitly state "We consider the case where a = super(B, obj), with `obj` an instance of B."

Also, `super(B, obj).m()` seems to indicate that the method `m` is called. While ` A.__dict__['m'].__get__(obj, obj.__class__)` does not seems to call this method. Hence, I believe that the parentheses should be removed after `m` (and either `m` should be renamed to `x`, or we should state explicitly that we are not considered `a.x` anymore, contrary to the previous cases)



In https://docs.python.org/3/library/functions.html#super , you can read 
> 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).

On first reading, I have no idea what it means that a returned object is unbound. I know what "variable binding" mean, but it really does not seems to apply here. My current understanding, and I would love if someone can confirm it, is that the first sentence means that "contrary to the other cases, the returned value do not have to satisfy any bound". In this case, I believe that it would be far better to put the case with no second argument at the end of the paragraph, ensuring that "is unbound" makes sens to the reader since they already will have seen bounds.
Also, it may help clarify to write "is an object `obj`" and "is a type `type2`" so that it get clear what `obj` and `type2` means.



Any feedback welcome.
msg409205 - (view) Author: Arthur Milchior (Arthur-Milchior) * Date: 2021-12-26 16:17
I just realized that https://bugs.python.org/issue20751 already tackled some of my issues. While I still believe that some things can be improved, this mean that some of the critiques in my first messages are not entirely up to date.
msg409207 - (view) Author: Arthur Milchior (Arthur-Milchior) * Date: 2021-12-26 16:27
"a base class ``B`` following ``A``" shouldn't it be "the base class"? . After all, there is at most one base class following ``A``.

Also, I find it unclear what means "``x`` is returned unchanged, since in this context ``x`` is not a value which exists by itself.
msg409217 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-12-26 20:35
> "a base class ``B`` following ``A``" shouldn't it  be "the base 
> class"? . After all, there is at most one base class following ``A``

No. There can be other classes in the chain.  The first to match the lookup wins.

> Also, it may help clarify to write "is an object `obj`" and 
> "is a type `type2`" so that it get clear what `obj` and `type2` means.

Sorry, but I don't your proposed wording adds value.  While you may feel that it is more precise, it just adds redundant words without adding information.  FWIW, we do this all over the docs, letting parameter names such as *obj* and *type2* communicate that we're referring to an object or a type.

> Hence, I believe that the parentheses should be removed after `m`

I took care of that in the other tracker issue.  That said, it arguably made the docs worse rather than better because by far the dominant use case for super() is calling methods rather than doing attribute lookup.  I only made the change to be consistent with the other attribute lookup examples.

> I find super documentation confusing because it uses multiple variables
> that are never introduced.

ISTM that you're looking for a full tutorial with fully worked worked out examples rather than English text interspersed with code snippets.  Consider reading the super-considered-super post for that purpose.

As for the existing text, I've wrestled with it for years and think we've hit a local optimum.  Expanding the text with more steps and descriptions of each step results in documentation that causes people's eyes to glaze over and to miss the main point of each sentence.

Also, remember that the documentation is factored.  The descriptor tutorial is primarily about descriptors.  A super() call is just one of four ways to invoke a descriptor.  From a descriptor howto point-of-view, all we want to communicate is that the attribute/method search starts at the next in the mro rather than the current instance.  It is not the goal of that section to fully document or discuss super().  

As for the main super() docs, that is the place talk about how super works; however, it is not the job of that section to explain the rest of Python (terms like bound, unbound, etc). In a way, the only job of this section is to differentiate how ``super(A, a).x`` differs from ``a.x``.  Other parts of the docs cover the general attribute lookup, C3 algorithm, method binding, etc.   The use of super() is just a special case where where the search starts from the class right after the given or inferred *type* argument.
msg409218 - (view) Author: Arthur Milchior (Arthur-Milchior) * Date: 2021-12-26 20:59
I do regret to have created a single bug, as I now realize that there are two issues that are less related than I first imagined. Is there a way to split a bug in two, so that both discussion can be discussed in different places.

Actually, after more search abound "unbound method", I discovered in https://www.python.org/download/releases/3.0/whatsnew/ that this concept was supposed to be gone for good in 3.0

The notion is also used in a few other places in the documentation but as far as I can tell the only "definition" would be in https://docs.python.org/3.11/c-api/method.html#method-objects. 
While my first suggestion here was clearly wrong, I believe it still indicates a documentation bug. In that if the concept is still in the language, "unbound" should be a link to this concept. If the concept is not in the language anymore, then it should not be used without explanation.
"super considered super" does not give a single example of super with a single argument. Which is probably great, because this case is far less super. However, this means that:
* there is currently no way for a user that want to discover python to know that there is virtually no more reason to use super with a single argument. 
* for someone reading a codebase with super called with a single argument, it would be hard to figure out what it does.

Actually, I was going to create a PR https://github.com/Arthur-Milchior/cpython/commit/dd453acad2b1f61867717cee4b47f944d37fb213 before seeing your answer, and while less certain, I still believe it has merits
msg409219 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-12-26 21:51
I'm reluctant to give any more space to the least important case, one that rarely arises in practice.  The text in the PR is wordy and IMO creates more confusion that it solves.

Per the dev-guide, we mostly avoid "preachy" text.  No, "it is recommended to avoid the single argument form".  In the unlikely event that a person needs this, we are not recommending against it.  It is in fact supported, tested, and mentioned in the documentation.  And to the extend we care to nudge users in one direction or another, the traditional way to deemphasize a feature is spend less time and space talking about it :-) 

At this point, I recommend just letting it be.  It feels like we're going down a rabbit hole here rather than solving problems that users actually have.  These features are almost two decades old and the docs have been stable for a long time.  If there were a significant communication issue here, we would have known long ago.

To gain an appreciation for the challenges we face in documentation, take a look at the discussion in https://bugs.python.org/issue46173 .  

In the case of super(), more words don't make the docs better; it just adds more text that a user has to fight through to get the gestalt of what is going on.  When I talk to advanced users of the language, they almost never think of super() in more detail than is covered in the docs; instead, they've grokked the central concept of next-in-mro and that it is commonly used in two ways either to call parent class or to implement cooperative multiple inheritance.  Ideally, we want to lead readers to that same understanding.  IMO, detailing the mechnanics of uncommon cases takes us in the opposite direction.
History
Date User Action Args
2022-04-11 14:59:53adminsetgithub: 90340
2022-01-03 00:34:31rhettingersetstatus: open -> closed
assignee: docs@python -> rhettinger
resolution: not a bug
stage: resolved
2021-12-26 21:51:54rhettingersetmessages: + msg409219
2021-12-26 20:59:08Arthur-Milchiorsetmessages: + msg409218
2021-12-26 20:35:55rhettingersetnosy: + rhettinger
messages: + msg409217
2021-12-26 16:27:23Arthur-Milchiorsetmessages: + msg409207
2021-12-26 16:17:56Arthur-Milchiorsetmessages: + msg409205
versions: - Python 3.11
2021-12-26 15:38:34Arthur-Milchiorcreate