classification
Title: Harmonize descriptor protocol documentation: direct call, super binding with Descriptor Howto docs
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: closed Resolution: not a bug
Dependencies: 12077 Superseder:
Assigned To: rhettinger Nosy List: docs@python, martin.panter, rhettinger, zuo
Priority: normal Keywords: patch

Created on 2014-02-23 22:13 by zuo, last changed 2021-12-04 02:39 by rhettinger. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 29909 merged rhettinger, 2021-12-03 23:47
Messages (5)
msg212035 - (view) Author: Jan Kaliszewski (zuo) Date: 2014-02-23 22:13
1. One misleading detail in the descriptor protocol documentation for super bindings is that the following fragment of the http://docs.python.org/reference/datamodel.html#invoking-descriptors page:

"""
Super Binding
    If a is an instance of super, then the binding super(B, obj).m() searches obj.__class__.__mro__ for the base class A immediately preceding B and then invokes the descriptor with the call: A.__dict__['m'].__get__(obj, obj.__class__).
"""

...introduces the method *call* (".m()") which AFAIK has nothing to do with the actual matter of the description (attribute resolution).

Also, the "If *a* is an instance of super" fragment is strange, as *a* is not used in the following sentences at all.

I believe the description should be:

"""
Super Binding
    If binding to a super instance, super(B, obj).x searches obj.__class__.__mro__ for the base class A immediately preceding B and then invokes the descriptor with the call: A.__dict__['x'].__get__(obj, obj.__class__).
"""

(using 'x' as the attribute name, as for the other kinds of binding).

***

2. Also, in some earlier fragment of the same page:

"""
Direct Call
    The simplest and least common call is when user code directly invokes a descriptor method: x.__get__(a).
"""

The call x.__get__(a) without the second argument seems to be wrong if  __get__ is implemented according to the specification "object.__get__(self, instance, owner)" from the same documentation page.
msg237709 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2015-03-09 21:37
Who is best placed to comment on the suggested docs changes given in msg212035?
msg294023 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2017-05-20 09:35
Lower-case “a” is defined at the top of the list: “The starting point . . . is ‘a.x’.” The last entry may fit in better if it was written “If binding to an instance of ‘super’ ”.

The problem with the m() call is also mentioned in Issue 25777, about the descriptor how-to.

Issue 12077 seems to be largely about the __get__ signature.
msg407617 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-12-03 23:39
Regarding comment #1, The wording is correct and there was a reason for using a method.  While super() can be used for attribute lookup, use cases are almost entirely dominated by method lookups.  For many users, an attribute lookup with super() is unconventional, weird, hard to grok, awkward to demonstrate, and not well motivated by the way super() is actually used.

    ##############################################################
    # Demonstration code for the example in text

    class A:
        def m(self):
            return 42

    class B(A):
        def m(obj):
            return super(B, obj).m()

    >>> b = B()
    >>> b.m()                             # Normal invocation 
    42
    >>> A.__dict__['m'].__get__(b, B)()   # Equivalent call
    42

That said, I will switch it to an attribute lookup for consistency with the other examples in the section and with the current version of the DescriptorHowto.


Regarding comment #2, the objtype argument is optional as shown in all of the examples.  The call from object.__getattribute__() always passes in both parameters, even though only the first is required.
  
    ################################################################
    # Demonstration of __get__() being called with one or two params

    class A:
        def __init__(self, x):
            self.x = x
        def m(self, y):
            return self.x * y

    >>> a = A(10)
    >>> a.m(5)
    50
    >>> vars(A)['m'].__get__(a)(5)     # objtype is not required
    50
    >>> vars(A)['m'].__get__(a, A)(5)  # objtype may be used
    50


    ################################################################
    # Demonstration of object.__getattribute__ supplying both args

    class Desc:
        def __get__(self, *args):
            return args
      
    class B:
        z = Desc()
     
    >>> b = B()
    >>> b.z
    (<__main__.B object at 0x109156110>, <class '__main__.B'>)
msg407627 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-12-04 02:37
New changeset 135ecc3492cee259090fd4aaed9056c130cd2eba by Raymond Hettinger in branch 'main':
bpo-20751:  Replace method example with attribute example, matching the descriptor howto (GH-29909)
https://github.com/python/cpython/commit/135ecc3492cee259090fd4aaed9056c130cd2eba
History
Date User Action Args
2021-12-04 02:39:44rhettingersetstatus: open -> closed
stage: patch review -> resolved
2021-12-04 02:37:15rhettingersetmessages: + msg407627
2021-12-03 23:47:23rhettingersetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request28134
2021-12-03 23:39:41rhettingersetresolution: not a bug
messages: + msg407617
2021-12-03 16:19:24rhettingersettitle: Misleading descriptor protocol documentation: direct call, super binding -> Harmonize descriptor protocol documentation: direct call, super binding with Descriptor Howto docs
2021-12-03 16:17:57rhettingersetassignee: docs@python -> rhettinger
2021-12-03 14:18:05iritkatrielsettype: behavior
versions: + Python 3.9, Python 3.10, Python 3.11, - Python 2.7, Python 3.5, Python 3.6, Python 3.7
2017-05-20 13:36:56BreamoreBoysetnosy: - BreamoreBoy
2017-05-20 09:35:51martin.pantersetdependencies: + Harmonizing descriptor protocol documentation

title: Misleading examples in the descriptor protocol documentation -> Misleading descriptor protocol documentation: direct call, super binding
nosy: + rhettinger, martin.panter
versions: + Python 2.7, Python 3.6, Python 3.7, - Python 3.4
messages: + msg294023
stage: needs patch
2015-03-09 21:37:59BreamoreBoysetnosy: + BreamoreBoy

messages: + msg237709
versions: + Python 3.5, - Python 3.1, Python 2.7, Python 3.2, Python 3.3
2014-02-23 22:51:39zuosettitle: Misleading examples indDescriptor protocol documentation -> Misleading examples in the descriptor protocol documentation
2014-02-23 22:13:56zuocreate