सरल रिप्रो:
class VocalDescriptor(object):
def __get__(self, obj, objtype):
print('__get__, obj={}, objtype={}'.format(obj, objtype))
def __set__(self, obj, val):
print('__set__')
class B(object):
v = VocalDescriptor()
B.v # prints "__get__, obj=None, objtype=<class '__main__.B'>"
B.v = 3 # does not print "__set__", evidently does not trigger descriptor
B.v # does not print anything, we overwrote the descriptor
इस सवाल का एक प्रभावी डुप्लिकेट है , लेकिन डुप्लिकेट का उत्तर नहीं दिया गया था, और मैंने सीपीथॉन स्रोत में सीखने के अभ्यास के रूप में थोड़ा और खोदा। चेतावनी: मैं मातम में चला गया। मैं वास्तव में उम्मीद कर रहा हूं कि मैं एक कप्तान से मदद ले सकता हूं जो उन पानी को जानता है । मैंने अपने भविष्य के लाभ और भविष्य के पाठकों के लाभ के लिए, उन कॉल को ट्रेस करने में जितना संभव हो सके उतना स्पष्ट होने की कोशिश की।
मैंने __getattribute__वर्णनकर्ताओं पर लागू किए गए व्यवहार पर बहुत सी स्याही देखी है , जैसे कि पूर्ववर्ती खोज। अजगर झलकी में "लागू वर्णनकर्ता" बस नीचे For classes, the machinery is in type.__getattribute__()...मोटे तौर पर मेरे मन में मैं क्या मानना है कि इसी है के साथ सहमत हैं CPython स्रोत में type_getattroहै, जो मैं देख कर नीचे ट्रैक किए गए "tp_slots" तो जहां tp_getattro से भर जाता है । और तथ्य यह है कि B.vशुरू में प्रिंट __get__, obj=None, objtype=<class '__main__.B'>मुझे समझ में आता है।
जो मुझे समझ नहीं आ रहा है, वह असाइनमेंट B.v = 3नेत्रहीन को ट्रिगर करने के बजाए नेत्रहीन को क्यों अधिलेखित करता है v.__set__? मैंने "tp_slots" से एक बार फिर से शुरू होने वाले CPython कॉल को ट्रेस करने की कोशिश की , फिर tp_setattro को पॉप्युलेट किया , फिर टाइप_सेट्टात्रो को देखते हुए । _PyObject_GenericSetAttrWithDict के आसपास एक पतला आवरण type_setattro प्रतीत होता है । और वहाँ मेरी उलझन की जड़ है: तर्क के लिए प्रतीत होता है जो एक विवरणक की विधि को पूर्वता देता है !! इसे ध्यान में रखते हुए, मैं यह पता नहीं लगा सकता कि क्यों आंखें मूंदने के बजाय आंखें मूंद कर लिखना चाहिए ।_PyObject_GenericSetAttrWithDict__set__B.v = 3vv.__set__
अस्वीकरण 1: मैंने प्रिंटआउट के साथ स्रोत से अजगर का पुनर्निर्माण नहीं किया, इसलिए मुझे पूरी तरह से यकीन नहीं type_setattroहै कि किस दौरान बुलाया जा रहा है B.v = 3।
डिस्क्लेमर 2: VocalDescriptor"विशिष्ट" या "अनुशंसित" डिस्क्रिप्टर परिभाषा को स्पष्ट करने का इरादा नहीं है। यह एक क्रिया है जो मुझे नहीं बताती है कि तरीकों को कब बुलाया जा रहा है।
__get__काम किया, बजाय इसके कि क्यों __set__नहीं किया।
__get__विधि लागू करने की उम्मीद कर रहा है । B.v = 3प्रभावी रूप से एक के साथ विशेषता को ओवरराइट कर दिया है int।
__get__है कि क्या कहा जाता है, और एक उदाहरण या वर्ग का उपयोग करते समय डिफ़ॉल्ट कार्यान्वयन object.__getattribute__और type.__getattribute__आह्वान __get__करता है। उदाहरण के माध्यम से ही असाइन करना__set__ है।
__get__तरीकों को ट्रिगर करने के लिए माना जाता है जब कक्षा से ही बुलाया जाता है। यह कैसे-कैसे गाइड के अनुसार @classmethods और @staticmethods कार्यान्वित किया जाता है । @ जाब मैं सोच रहा हूँ कि B.v = 3क्लास डिस्क्रिप्टर को ओवरराइट करने में सक्षम क्यों है। CPython कार्यान्वयन के आधार पर, मुझे B.v = 3भी ट्रिगर की उम्मीद थी __set__।