सरल रिप्रो:
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 = 3
v
v.__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__
।