You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Docs: Descript __get__ signature defined differently across the docs #80924
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=<Date2019-08-29.08:28:45.230>created_at=<Date2019-04-27.17:56:43.412>labels= ['3.7', '3.8', 'docs']
title='Docs: Descript __get__ signature defined differently across the docs'updated_at=<Date2019-08-29.09:02:55.421>user='https://github.com/jdufresne'
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.
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 3.3.2.3 already has an example of a direct call to a __get__ descriptor with only the *obj* argument.
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.
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.
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:
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):
print(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'>
New changeset c71ae1a by Raymond Hettinger (Miss Islington (bot)) in branch '3.8': bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH-15589) c71ae1a
Activity
jdufresne commentedon Apr 27, 2019
Here: https://docs.python.org/3/reference/datamodel.html#object.\_\_get__
The __get__ signature is defined as:
But here: https://docs.python.org/3/howto/descriptor.html#descriptor-protocol
It is defined as:
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.
rhettinger commentedon Apr 28, 2019
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 3.3.2.3 already has an example of a direct call to a __get__ descriptor with only the *obj* argument.
jdemeyer commentedon May 3, 2019
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.
jdemeyer commentedon May 3, 2019
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.
rhettinger commentedon Aug 29, 2019
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 @property def p(self): return 43 @classmethod def c(cls): return 44 @staticmethod def s(): return 45 >>> a = A() >>> vars(A)['m'].__get__(a)() 42 >>> vars(A)['m'].__get__(a, A)() 42 >>> vars(A)['p'].__get__(a) 43 >>> vars(A)['p'].__get__(a, A) 43 >>> vars(A)['c'].__get__(a)() 44 >>> vars(A)['c'].__get__(a, A)() 44 >>> vars(A)['s'].__get__(a)() 45 >>> vars(A)['s'].__get__(a, A)() 45Python 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): print(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'>rhettinger commentedon Aug 29, 2019
New changeset 0dac68f by Raymond Hettinger in branch 'master':
bpo-36743: __get__ is sometimes called without the owner argument (bpo-12992)
0dac68f
rhettinger commentedon Aug 29, 2019
New changeset c71ae1a by Raymond Hettinger (Miss Islington (bot)) in branch '3.8':
bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH-15589)
c71ae1a