I noticed that contrary to the classmethod and staticmethod decorators, the property decorator overrides the object.__getattribute__ method:
>>> list(vars(classmethod))
['__new__', '__repr__', '__get__', '__init__', '__func__', '__wrapped__', '__isabstractmethod__', '__dict__', '__doc__']
>>> list(vars(staticmethod))
['__new__', '__repr__', '__call__', '__get__', '__init__', '__func__', '__wrapped__', '__isabstractmethod__', '__dict__', '__doc__']
>>> list(vars(property))
['__new__', '__getattribute__', '__get__', '__set__', '__delete__', '__init__', 'getter', 'setter', 'deleter', '__set_name__', 'fget', 'fset', 'fdel', '__doc__', '__isabstractmethod__']
The functionality of the property decorator doesn’t seem to require this override (cf. the equivalent Python code in the Descriptor HowTo Guide). So which behaviour exactly does this override implement? Please provide a link to the corresponding C code in the CPython repository, and optionally an equivalent Python code.
To refresh yourself on what
__getattribute__is and how this is implemented in CPython, please refer to this very excellent answer first, as that answers contains all the detailed background information on what to look for in the CPython source, and the paragraphs below will reference those details without further explanations.In CPython, all builtin types (e.g.
object,int,str,float) all follow a standard way on how they are defined. These builtin types with their dunder methods are all slotted in the underlying C implementation, for examplefloatsimply reference the defaultPyObject_GenericGetAttrfortp_getattro, and this is exactly the same forproperty. Essentially, the descriptor howto guide is correct in omitting any references to__getattribute__, as its presence is nothing more than an artifact on how builtin types in Python are defined (i.e. they all point to the same generic implementation for "the normal way of looking for object attributes" if it's just a pointer to the aptly namedPyObject_GenericGetAttr).As for why
classmethoddoes not have__getattribute__appear as part of itsvarsoutput, that's because the definition forclassmethoddoes not includetp_getattronortp_getattr, but it just means that its__getattribute__falls back to its parent's, which isobject.__getattribute__(check in Python for output ofclassmethod.__getattribute__ is object.__getattribute__). As for whyclassmethodis defined without the explicit linkage while various other builtin types define an explicit linkage toPyObject_GenericGetAttr(despite the outcome of either decisions being functionally the same in nearly all code usage), you may have to ask the developers themselves.Addendum: though at some point 12 years ago (2012), around the time of Python 3.2 was being developed,
classmethoddid havetp_getattroset, but subsequent to that commit2cf936fe7a55(included since 2.7.5 and 3.3.0a1) - the commit message has no hints as to why it was simply changed to "use defaults". As forfloatandpropertytype, the change was introduced way back in the merge commit6d6c1a35e08bfrom nearly 22 years ago (2001) that brought in the changes outlined in PEP-252 which is the descriptor protocol itself. Note that it set alltp_getattrotoPyObject_GenericGetAttrfor standard types that didn't have it defined before (and likewise forclassmethodwhich is where this type made its debut).