classification
Title: Descriptor protocol documentation for super bindings is incorrect
Type: Stage:
Components: Documentation Versions: Python 3.1, Python 3.2, Python 3.3, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: Joshua.Arnold, docs@python, python-dev, rhettinger
Priority: normal Keywords:

Created on 2011-01-23 18:38 by Joshua.Arnold, last changed 2011-03-22 22:34 by rhettinger. This issue is now closed.

Messages (4)
msg126895 - (view) Author: Joshua Arnold (Joshua.Arnold) Date: 2011-01-23 18:38
In 'Doc/reference/datamodel.rst', the 'Invoking Descriptors' documentation specifies the following behavior for super objects:

[snip]
Super Binding
   If ``a`` is an instance of :class:`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, A)``.
[snip]

In the above paragrah, the call:

   A.__dict__['m'].__get__(obj, A)
   
is incorrect.  In reality, the descriptor is invoked via:

   A.__dict__['m'].__get__(obj, obj.__class__)
   
Loosely speaking, the 'owner' argument is set to the subclass associated with the super object, not the superclass.  There is a similar error in the 'Descriptor HowTo Guide' under 'Invoking Descriptors'

(Strictly speaking, the specification is inaccurate on some other points.  It assumes obj is not a class and doesn't state that the entire mro preceding 'B' is searched for 'm'.  But those may be considered simplifications for the sake of brevity)

I considered reporting this as a bug in the implementation rather than the specification.  But I think the implementation's algorithm is the correct one.  In particular, it yields the desired behavior for classmethods   In any case, the current behavior has been around for a while (it was the fix for issue #535444, dating back to 2.2)

Code demonstrating the current behavior:

class Desc(object):
    def __get__(self, instance, owner):
        return owner

class A(object):
    attr = Desc()

class B(A):
    pass

class C(B):
    pass

instance = C()

assert super(B,instance).attr == C
assert super(B,C).attr == C

#According to the specification, the assertions should be:
#assert super(B,instance).attr == A
#assert super(B,C).attr == A
msg131795 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-03-22 22:29
New changeset 50cc60852a76 by Raymond Hettinger in branch '2.7':
Issue 10988: fix description of super's descriptor call.
http://hg.python.org/cpython/rev/50cc60852a76
msg131796 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-03-22 22:34
New changeset 3e3c46a3dce8 by Raymond Hettinger in branch '3.1':
Issue 10988: fix description of super's descriptor call.
http://hg.python.org/cpython/rev/3e3c46a3dce8

New changeset 40698c68a32c by Raymond Hettinger in branch '3.2':
Issue 10988: fix description of super's descriptor call.
http://hg.python.org/cpython/rev/40698c68a32c

New changeset 29c8eb206076 by Raymond Hettinger in branch 'default':
Issue 10988: fix description of super's descriptor call.
http://hg.python.org/cpython/rev/29c8eb206076
msg131797 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2011-03-22 22:34
Fixed.
Thanks for the bug report.
History
Date User Action Args
2011-03-22 22:34:40rhettingersetstatus: open -> closed

messages: + msg131797
resolution: fixed
versions: + Python 3.3, - Python 2.6, Python 2.5
2011-03-22 22:34:10python-devsetmessages: + msg131796
2011-03-22 22:29:28python-devsetnosy: + python-dev
messages: + msg131795
2011-01-23 19:56:06rhettingersetassignee: docs@python -> rhettinger

nosy: + rhettinger
2011-01-23 18:38:03Joshua.Arnoldcreate