Skip to content

super() documentation isn't very clear #67862

Closed

Description

@TapaniKiiskinen
BPO 23674
Nosy @rhettinger, @bitdancer, @vadmium, @mhsmith, @csabella
PRs
  • bpo-23674: Clarify ambiguities in super() docs #15564
  • [3.8] bpo-23674: Clarify ambiguities in super() docs (GH-15564) #15585
  • [3.8] bpo-23674: Clarify ambiguities in super() docs (GH-15564) #15586
  • Files
  • super.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/rhettinger'
    closed_at = <Date 2019-08-29.07:56:22.871>
    created_at = <Date 2015-03-15.19:40:51.514>
    labels = ['docs']
    title = "super() documentation isn't very clear"
    updated_at = <Date 2019-08-29.08:03:04.812>
    user = 'https://bugs.python.org/TapaniKiiskinen'

    bugs.python.org fields:

    activity = <Date 2019-08-29.08:03:04.812>
    actor = 'rhettinger'
    assignee = 'rhettinger'
    closed = True
    closed_date = <Date 2019-08-29.07:56:22.871>
    closer = 'rhettinger'
    components = ['Documentation']
    creation = <Date 2015-03-15.19:40:51.514>
    creator = 'Tapani Kiiskinen'
    dependencies = []
    files = ['41255']
    hgrepos = []
    issue_num = 23674
    keywords = ['patch']
    message_count = 14.0
    messages = ['238157', '238159', '238162', '238196', '255685', '256004', '291348', '293986', '294012', '294026', '294042', '298365', '350744', '350749']
    nosy_count = 7.0
    nosy_names = ['rhettinger', 'r.david.murray', 'docs@python', 'martin.panter', 'Malcolm Smith', 'Tapani Kiiskinen', 'cheryl.sabella']
    pr_nums = ['15564', '15585', '15586']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue23674'
    versions = ['Python 2.7', 'Python 3.4', 'Python 3.5', 'Python 3.6']

    Activity

    1. TapaniKiiskinen commented on Mar 15, 2015

      TapaniKiiskinenmannequin
      MannequinAuthor

      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.

    2. rhettinger commented on Mar 15, 2015

      @rhettinger
      Contributor

      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.

    3. bitdancer commented on Mar 15, 2015

      @bitdancer
      Member

      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?

    4. TapaniKiiskinen commented on Mar 16, 2015

      TapaniKiiskinenmannequin
      MannequinAuthor

      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.

    5. vadmium commented on Dec 2, 2015

      @vadmium
      Member

      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 bpo-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 bpo-20503. Also, the first argument should be a derived class, not “object” itself.

    6. vadmium commented on Dec 6, 2015

      @vadmium
      Member

      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.

    7. vadmium commented on Apr 9, 2017

      @vadmium
      Member

      The magical no-argument call could also be clarified:

      1. 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).

      2. 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.

    8. csabella commented on May 19, 2017

      @csabella
      Contributor

      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.

    9. rhettinger commented on May 20, 2017

      @rhettinger
      Contributor

      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.

    10. vadmium commented on May 20, 2017

      @vadmium
      Member

      Cheryl: see also bpo-25777 and bpo-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.

    11. csabella commented on May 20, 2017

      @csabella
      Contributor

      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.

    12. mhsmith commented on Jul 14, 2017

      mhsmithmannequin
      Mannequin

      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.

    13. rhettinger commented on Aug 29, 2019

      @rhettinger
      Contributor

      New changeset cd81f05 by Raymond Hettinger in branch 'master':
      bpo-23674: Clarify ambiguities in super() docs (bpo-15564)
      cd81f05

    14. rhettinger commented on Aug 29, 2019

      @rhettinger
      Contributor

      New changeset 43b7ed7 by Raymond Hettinger (Miss Islington (bot)) in branch '3.8':
      bpo-23674: Clarify ambiguities in super() docs (GH-15564) (GH-15586)
      43b7ed7

    15. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    docsDocumentation in the Doc dir

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions