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
Contradiction in definition of "data descriptor" between (dotted lookup behavior/datamodel documentation) and (inspect lib/descriptor how-to) #70291
Data descriptors have both a __get__ and a __set__ attribute..."""
if isclass(object) or ismethod(object) or isfunction(object):
# mutual exclusion
return False
tp = type(object)
return hasattr(tp, "__set__") and hasattr(tp, "__get__")
I'm willing to sign a contributor release and fix myself.
This isn't just a documentation issue since it fixes inspect.isdatadescriptor(). I confirm that the new implementation better matches the C code. LGTM, but needed tests for inspect.isdatadescriptor() and a Misc/NEWS entry.
New changeset 4054b17 by Serhiy Storchaka (Aaron Hall, MBA) in branch 'master': bpo-26103: Fix inspect.isdatadescriptor() and a data descriptor definition. (GH-1959) 4054b17
I suspect that this issue was resolved in the wrong direction. It is meaningless and not useful to define something as a "data descriptor" that does not have a __get__ method, since the only implication of something being a "data descriptor" is that its __get__ method takes precedence over the instance dict. But obviously this "taking precedence" cannot occur when the descriptor has no __get__ method. So I think it is more useful to clarify that data descriptors must have both __get__ and either or both of __set__ and __delete__.
The reason PyDescr_IsData does not explicitly check for tp_descr_get is that, in every case where it's used, the accompanying step (either immediately before or after the PyDescr_IsData check) is to actually fetch tp_descr_get from the descriptor; if it is NULL, then attribute-getting always proceeds exactly as if the descriptor were not a data descriptor. (In fact, in 3/4 call sites the check is literally (descr_get != NULL && PyDescr_IsData(descr).) So also checking existence of tp_descr_get within PyDescr_IsData would be redundant in every place it is used. But the end-to-end behavior in all these cases is that descriptors without tp_descr_get behave exactly the same as non-data descriptors. I don't think we want PyDescr_IsData to do the redundant check (these are hot code paths; though tbh compilers might be smart enough to eliminate it anyway), maybe it should be renamed for better clarity?
I'm not sure whether this is important enough to file a new issue and fix. The main case where I can see it might cause confusion is that e.g. if inspect.getattr_static hewed blindly to the currently-documented definition of what makes a data descriptor, it would wrongly return the descriptor object instead of the instance dict value for descriptors without __get__. (Fortunately it doesn't follow the documented definition, but also checks for __get__.) This came up in #75367.
Activity
aaronchall commentedon Jan 13, 2016
Based on the data-model documentation (https://docs.python.org/2/reference/datamodel.html#invoking-descriptors) and the dotted lookup behavior, the follow definitions are correct:
"If the descriptor defines __set__() and/or __delete__(), it is a data descriptor; if it defines neither, it is a non-data descriptor."
However, the inspect module has the following, which is also reflected in the descriptor how-to (https://docs.python.org/2/howto/descriptor.html#descriptor-protocol):
"If an object defines both __get__() and __set__(), it is considered a data descriptor."
I'm willing to sign a contributor release and fix myself.
aaronchall commentedon Jun 5, 2017
Bumping this - I intend to work on this next, if no objections.
serhiy-storchaka commentedon Jun 6, 2017
This isn't just a documentation issue since it fixes inspect.isdatadescriptor(). I confirm that the new implementation better matches the C code. LGTM, but needed tests for inspect.isdatadescriptor() and a Misc/NEWS entry.
aaronchall commentedon Jun 6, 2017
Added news, working on tests
Mariatta commentedon Jun 6, 2017
Please also add yourself to Misc/ACKS.
aaronchall commentedon Jun 6, 2017
Done!
aaronchall commentedon Jun 8, 2017
I tweaked the docs a little more this morning, but I believe I am done making any further changes unless so requested.
This issue doesn't say it's assigned to anyone. Is there anything else that needs to happen here?
aaronchall commentedon Sep 4, 2017
Serhiy,
Not sure what else needs to be done to wrap this up. All checks are passing on the pull request.
Thoughts?
serhiy-storchaka commentedon Sep 21, 2017
The only question is remained -- should *data descriptors* be *descriptors*? I.e. is the __get__ method required for data descriptors?
chnlior commentedon Dec 11, 2017
Joining @serhiy Storchaka last question.
Is the __get__ method existance is a must be a data descriptor?
According to the C implementation in descrobject.h
the answer is No.
Does this C code reflect the true definition?
serhiy-storchaka commentedon May 20, 2018
New changeset 4054b17 by Serhiy Storchaka (Aaron Hall, MBA) in branch 'master':
bpo-26103: Fix inspect.isdatadescriptor() and a data descriptor definition. (GH-1959)
4054b17
csabella commentedon Mar 20, 2019
It looks like this issue can be closed now that it's merged?
carljm commentedon Apr 6, 2023
I suspect that this issue was resolved in the wrong direction. It is meaningless and not useful to define something as a "data descriptor" that does not have a
__get__method, since the only implication of something being a "data descriptor" is that its__get__method takes precedence over the instance dict. But obviously this "taking precedence" cannot occur when the descriptor has no__get__method. So I think it is more useful to clarify that data descriptors must have both__get__and either or both of__set__and__delete__.The reason
PyDescr_IsDatadoes not explicitly check fortp_descr_getis that, in every case where it's used, the accompanying step (either immediately before or after thePyDescr_IsDatacheck) is to actually fetchtp_descr_getfrom the descriptor; if it isNULL, then attribute-getting always proceeds exactly as if the descriptor were not a data descriptor. (In fact, in 3/4 call sites the check is literally(descr_get != NULL && PyDescr_IsData(descr).) So also checking existence oftp_descr_getwithinPyDescr_IsDatawould be redundant in every place it is used. But the end-to-end behavior in all these cases is that descriptors withouttp_descr_getbehave exactly the same as non-data descriptors. I don't think we wantPyDescr_IsDatato do the redundant check (these are hot code paths; though tbh compilers might be smart enough to eliminate it anyway), maybe it should be renamed for better clarity?I'm not sure whether this is important enough to file a new issue and fix. The main case where I can see it might cause confusion is that e.g. if
inspect.getattr_statichewed blindly to the currently-documented definition of what makes a data descriptor, it would wrongly return the descriptor object instead of the instance dict value for descriptors without__get__. (Fortunately it doesn't follow the documented definition, but also checks for__get__.) This came up in #75367.