2017-05-02 8 views
9

type.__setattr__ कक्षाओं के लिए उपयोग किया जाता है, मूल रूप से मेटाक्लास के उदाहरण। दूसरी ओर object.__setattr__, कक्षाओं के उदाहरणों के लिए प्रयोग किया जाता है। यह पूरी तरह से समझा जाता है।ऑब्जेक्ट से टाइप .__ setattr__ कितना अलग है .__ setattr__?

मैं दो विधि बीच एक महत्वपूर्ण अंतर नहीं दिख रहा है, कम से कम अजगर स्तर पर, मैं नोटिस दो विशेषता काम के लिए एक ही प्रणाली का उपयोग करते है, मुझे ठीक कर लें मैं गलत हूँ:

मान लीजिए a है उपयोगकर्ता परिभाषित वर्ग का एक उदाहरण, सिर्फ एक सामान्य वर्ग:

class A: 
    pass 

a = A() 
a.x = ... 

तो a.x = .. invokes type(a).__setattr__(...) जो निम्न चरणों का पालन करता है:

नोट: 012,object builtin वर्ग

1) type(a).__mro__ में एक डेटा वर्णनकर्ता के लिए देखो में __setattr__ मिल जाएगा।

2) यदि कोई डेटा डिस्क्रिप्टर मिला, तो __set__ विधि और बाहर निकलें।

3) कोई डेटा वर्णनकर्ता type(a).__mro__ में पाया गया था, तो विशेषता a.__dict__ को जोड़ने के लिए, a.__dict__['x'] = ...


के साथ कक्षाएं

- metaclasses के उदाहरण, प्रक्रिया समान है:

class A(metaclass=type): 
    pass 

तो : A.x = ... का अनुवाद type(A).__setattr__(...) है जो निम्न चरणों का पालन करता है:

नोट: type(A).__setattr__type builtin वर्ग

1) type(A).__mro__

2 में एक डेटा वर्णनकर्ता के लिए देखो) यदि एक डेटा वर्णनकर्ता पाया गया था, अपने __set__ विधि और बाहर निकलने फोन में __setattr__ मिल जाएगा।

3) कोई डेटा वर्णनकर्ता type(A).__mro__ में पाया गया था, तो विशेषता A.__dict__ को जोड़ने, a.__dict__['x'] = ...

लेकिन object.__setattr__ वर्गों के लिए काम नहीं करता:

>>> object.__setattr__(A, 'x', ...) 
TypeError: can't apply this __setattr__ to type object 

और इसके विपरीत, type.__setattr__ नहीं है A के उदाहरणों के लिए काम:

>>> type.__setattr__(A(), 'x', ...) 
TypeError: descriptor '__setattr__' requires a 'type' object but received a 'A' 

हमम! दो तरीकों के बीच कुछ अलग होना चाहिए। यह सूक्ष्म है, लेकिन फिर भी सच है!

मुमकिन दो विधियों प्रदर्शन __setattr__ अंदर एक ही कदम, type.__setattr__ और इतने object.__setattr__ के बीच अंतर यह है कि type.__setattr__ वर्गों तक ही सीमित है और object.__setattr__ वर्गों के उदाहरण के लिए सीमित है क्या है?

उत्तर

7

type.__setattr__ में int जैसे प्रकारों पर सेटिंग विशेषता को रोकने के लिए एक चेक है, और यह सामान्य वस्तुओं के लिए अदृश्य क्लीनअप का एक गुच्छा नहीं है।


चलो हुड के नीचे एक नज़र डालें! यहाँ type.__setattr__ है:

static int 
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) 
{ 
    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { 
     PyErr_Format(
      PyExc_TypeError, 
      "can't set attributes of built-in/extension type '%s'", 
      type->tp_name); 
     return -1; 
    } 
    if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) 
     return -1; 
    return update_slot(type, name); 
} 

और अगर हम PyBaseObject_Type की जांच, हम इसे अपने __setattr__, एक ही कॉल type_setattro के माध्यम से आधे रास्ते प्रतीत होता है कि के लिए PyObject_GenericSetAttr का उपयोग करता है देखते हैं।

इस प्रकार, type.__setattr__object.__setattr__ जैसा है, लेकिन इसके आसपास कुछ अतिरिक्त हैंडलिंग लपेटा गया है।

पहले, if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) जांच,, सी में लिखे int या numpy.array तरह प्रकार पर विशेषता काम पर प्रतिबंध लगाता है, क्योंकि उन पर बताए गुण गंभीरता से तरीके कोई सी एपीआई उम्मीद नहीं कर के साथ अपरिचित में अजगर internals अप पेंच कर सकते हैं।

दूसरा, PyObject_GenericSetAttr कॉल अद्यतन करता है प्रकार के dict या metaclass से एक उचित वर्णनकर्ता कहता है, update_slot फिक्स किसी भी स्लॉट्स विशेषता काम से प्रभावित होने के बाद। ये स्लॉट सी-स्तरीय फ़ंक्शन पॉइंटर्स हैं जो आवृत्ति आवंटन, in चेक, +, डिलोकेशन इत्यादि जैसी कार्यक्षमता को कार्यान्वित करते हैं। उनमें से अधिकतर __contains__ या __add__ जैसे पाइथन-स्तर विधियों के अनुरूप हैं, और यदि उन पायथन-स्तर विधियों में से एक को फिर से सौंप दिया गया है , संबंधित स्लॉट (या स्लॉट) को भी अपडेट किया जाना है। update_slot कक्षा के सभी वंशजों पर स्लॉट भी अपडेट करता है, और यह ऑब्जेक्ट विशेषताओं के प्रकार के लिए उपयोग की जाने वाली आंतरिक विशेषता कैश में प्रविष्टियों को अमान्य करता है।

+0

आपके द्वारा उल्लेखित दूसरे चरण के बारे में एक प्रश्न। आइए मान लें कि 'क्लास' प्रारंभ में '__contains__' के बिना शुरू हुआ था। और कक्षा के निर्माण के बाद '__contains__' असाइन किया गया था। अगर मैं किसी वर्ग को असाइन करता हूं जैसे:' Klass .__ include__ = ... ', 'PyObject_GenericSetAttr'' Klass .__ dict__' और 'update_slot' अपडेट करेगा' __contain__'? इसका मतलब है 'क्लास' के लिए '__contains__' स्लॉट प्रारंभ में' शून्य 'असाइनमेंट से पहले था? – direprobs

+1

@direprobs: 'update_slot'' __contains__' से संबंधित स्लॉट सेट करेगा। वह स्लॉट '-> tp_as_sequence-> sq_contains' है, और केवल 'sq_contains' शून्य से अधिक है, हो सकता है कि यह अभी भी अस्तित्व में न हो, क्योंकि' tp_as_sequence' स्वयं शून्य हो सकता था। (इनमें से कोई भी आपके लिए तब तक महत्वपूर्ण नहीं होना चाहिए जब तक आपको सी एपीआई के साथ काम करने की आवश्यकता न हो।) – user2357112

संबंधित मुद्दे