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.

Title: Docs: Descript __get__ signature defined differently across the docs
Type: Stage: resolved
Components: Documentation Versions: Python 3.8, Python 3.7
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: docs@python, jdemeyer, jdufresne, rhettinger
Priority: normal Keywords: patch

Created on 2019-04-27 17:56 by jdufresne, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 12992 merged rhettinger, 2019-04-28 08:11
PR 15589 merged miss-islington, 2019-08-29 08:27
Messages (7)
msg341004 - (view) Author: Jon Dufresne (jdufresne) * Date: 2019-04-27 17:56

The __get__ signature is defined as:

object.__get__(self, instance, owner)

But here:

It is defined as:

descr.__get__(self, obj, type=None)

It is not clear to me as a reader if all descriptors should have the owner/type argument default to None or if it should be required. If it should default to None, I think all doc examples should follow this expectation to make it clear to someone implementing a descriptor for the first time. As best I can tell, the owner/type is always passed. So perhaps the =None shouldn't be there.

Grepping the CPython code, I see lots of definitions for both required and optional, adding more confusion for me.

If there is a definitive answer, I'm happy to follow through by updating the docs.
msg341023 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-04-28 07:12
Perhaps the datamodel docs can be clarified to note that callers are allowed to omit the third argument (which usually only makes sense when the second argument is not None). FWIW, section already has an example of a direct call to a __get__ descriptor with only the *obj* argument.
msg341333 - (view) Author: Jeroen Demeyer (jdemeyer) * (Python triager) Date: 2019-05-03 12:27
Personally, I have always found "instance" and "owner" very confusing names for these arguments. If you want to change the documentation, I would recommend changing those names too. Better names would be "obj" and "cls" or something like that.
msg341334 - (view) Author: Jeroen Demeyer (jdemeyer) * (Python triager) Date: 2019-05-03 12:42
> Perhaps the datamodel docs can be clarified to note that callers are allowed to omit the third argument

That's not true in general, only when __get__ is a slot wrapper (i.e. for classes implemented in C). When __get__ is a Python function, nothing special is done, it's just a Python function.
msg350708 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-08-29 04:51
Collecting various factlets on this topic

PEP 252 gives the specification for the descriptor protocol: "__get__(): a function callable with one or two arguments that retrieves the attribute value from an object."

function_get, property_get, classmethod_get, and staticmethod_get all support calls with one or two arguments:

    >>> a = A()
    >>> class A:
            def m(self):
                return 42
            def p(self):
                return 43
            def c(cls):
                return 44
            def s():
                return 45
    >>> a = A()
    >>> vars(A)['m'].__get__(a)()
    >>> vars(A)['m'].__get__(a, A)()
    >>> vars(A)['p'].__get__(a)
    >>> vars(A)['p'].__get__(a, A)
    >>> vars(A)['c'].__get__(a)()
    >>> vars(A)['c'].__get__(a, A)()
    >>> vars(A)['s'].__get__(a)()
    >>> vars(A)['s'].__get__(a, A)()

Python functions that comply with the specification should also do the same (as taught by the descriptor HOWTO).  That said, I have found multiple Python functions that aren't providing the None default.  I will fix those as I find them.

type.__getattribute__, object.__getattribute__ and super.__getattribute__ always call __get__ with both attributes specified:

    >>> class D:
            def __get__(*args):

    >>> class C:
            d = D()

    >>> class S(C):
            def f(self):
                return super().d
    >>> C.d
    (<__main__.D object at 0x104d967f0>, None, <class '__main__.C'>)
    >>> C().d
    (<__main__.D object at 0x104d967f0>, <__main__.C object at 0x104df77c0>, <class '__main__.C'>)
    >>> S().f()
    (<__main__.D object at 0x104d967f0>, <__main__.S object at 0x104df7580>, <class '__main__.S'>
msg350755 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-08-29 08:27
New changeset 0dac68f1e593c11612ed54af9edb865d398f3b05 by Raymond Hettinger in branch 'master':
bpo-36743: __get__ is sometimes called without the owner argument (#12992)
msg350759 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-08-29 09:02
New changeset c71ae1a45bd6e6d0f5aebc470b35f5a7dc0d8078 by Raymond Hettinger (Miss Islington (bot)) in branch '3.8':
bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH-15589)
Date User Action Args
2022-04-11 14:59:14adminsetgithub: 80924
2019-08-29 09:02:55rhettingersetmessages: + msg350759
2019-08-29 08:28:45rhettingersetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-08-29 08:27:54miss-islingtonsetpull_requests: + pull_request15265
2019-08-29 08:27:45rhettingersetmessages: + msg350755
2019-08-29 04:51:58rhettingersetmessages: + msg350708
2019-05-03 12:42:13jdemeyersetmessages: + msg341334
2019-05-03 12:27:51jdemeyersetnosy: + jdemeyer
messages: + msg341333
2019-04-28 08:11:19rhettingersetkeywords: + patch
stage: patch review
pull_requests: + pull_request12915
2019-04-28 07:12:09rhettingersetassignee: docs@python -> rhettinger
messages: + msg341023
versions: - Python 2.7, Python 3.5, Python 3.6, Python 3.9
2019-04-27 18:06:22xtreaksetnosy: + rhettinger
2019-04-27 17:56:43jdufresnecreate