2016-07-07 5 views
7

this उत्तर में मुझे पायथन में वस्तुओं की संदर्भ संख्या प्राप्त करने का एक तरीका मिला।पाइथन रेफ क्यों छोटे पूर्णांक को आश्चर्यजनक रूप से उच्च मानते हैं?

वे sys.getrefcount() का उपयोग कर उल्लेख किया है। मैंने कोशिश की, लेकिन मुझे एक अप्रत्याशित परिणाम मिल रहा है। जब 1 संदर्भ होता है, ऐसा लगता है कि गिनती 20 है। वह क्यों है?

मैं documentation को देखा, लेकिन यह कारण की व्याख्या करने के लिए प्रतीत नहीं होता।

enter image description here

+1

'sys.getrefcount (257) 'आज़माएं और यह शायद स्पष्ट रूप से गिर जाएगी। –

+0

एक दिलचस्प संख्या के लिए 'sys.getrefcount (कोई नहीं) 'आज़माएं। – cdarke

+1

वास्तव में अजीब बात है, मैंने कभी भी 257 के साथ एक var बनाया नहीं है। यह 3 क्यों वापस आता है? –

उत्तर

5

इस वस्तु पहले sys.getrefcount कॉल के समय यह करने के लिए 20 संदर्भ के लिए होता है। यह केवल आपके द्वारा बनाए गए संदर्भ नहीं है; वहाँ अन्य मॉड्यूल में और अजगर internals में इसे करने के लिए अन्य संदर्भ के सभी प्रकार के कर रहे हैं, के बाद से (यह एक कार्यान्वयन विस्तार है) अजगर के मानक कार्यान्वयन केवल एक 100 वस्तु बनाता है और एक अजगर कार्यक्रम में 100 की सभी घटनाओं के लिए इसे इस्तेमाल करता है।

+0

दिलचस्प, जानना अच्छा है, धन्यवाद! –

+1

अधिक प्रासंगिक, यदि आप अपनी ऑब्जेक्ट्स (सूचियां, टुपल्स, क्लास इंस्टेंस) बनाते हैं, तो आपको अपेक्षित व्यवहार मिल जाएगा। – alexis

5
वहाँ एक वस्तु कई संदर्भों होने के कारणों में से एक गुच्छा

। यह ट्रैक करना कि कौन सा मुश्किल हो सकता है, और यह तय करने के लिए कि क्या यह इसके लायक है, आपके ब्याज के स्तर को बाईपास कर सकता है। रेफरेंस गिनती डीबगिंग अनुप्रयोगों और पायथन संस्करणों के डेवलपर्स के लिए प्राथमिक रुचि है।

  • पायथन प्रत्येक संदर्भ में केवल एक वास्तविक मान रखने की कोशिश करता है। तो, आपके उदाहरण में आपके पास 100 वही 100 होगा जो रिकर्सन कॉल पर कुछ आंतरिक सीमा या वर्तमान लूप इंडेक्स के समान 100 है।
  • पायथन कम पूर्णांक सहित कुछ सामान्य वस्तुओं के अतिरिक्त संदर्भ रखता है। 1,234,567 के संदर्भ गिनती 20
  • कई कार्यों memoize को गिनती से अलग है, और हाल ही में बहस करने के लिए, संदर्भ रहते हैं।
  • कुछ दुभाषिया हाल के लाइनों पर संदर्भित हाल के मूल्यों और मानों के संदर्भ रखते हैं। उदाहरण के लिए, पिछले वापसी मान "_" में संग्रहीत है। इसका मतलब है दुभाषिया में चलना और कमांड लाइन से चलना अलग-अलग उत्तर देगा।
  • सभी संदर्भ गिनती योजनाओं की तरह, गलतियां हैं। उदाहरण के लिए, PyTuple_GetItem() में कुछ संदिग्ध विकल्प हैं।

सटीक संदर्भ गणना और उन गणनाओं के अर्थ पीपीआई बनाम सी-पायथन बनाम आईपीथन में भिन्न होंगे। पाइथन में अजीब व्यवहार खोजने के लिए संदर्भ गणना शायद ही कभी एक अच्छा उपकरण है।

4

यह Python2.7 जो बहुत अच्छी तरह से लिखा गया है और पढ़ने के लिए स्पष्ट है के लिए स्रोत कोड को पढ़ने के लिए मजेदार है। (यदि आप घर पर खेलना चाहते हैं तो मैं संस्करण 2.7.12 का जिक्र कर रहा हूं।) कोड को समझने के लिए एक अच्छी जगह व्याख्यान की उत्कृष्ट श्रृंखला है: C Python Internals जो शुरुआती परिप्रेक्ष्य से शुरू होती है।

हमारे लिए प्रासंगिक महत्वपूर्ण कोड (सी में लिखा गया) फ़ाइल 'ऑब्जेक्ट्स/intobject.c' में दिखाई देता है (मैंने कुछ #ifdef कोड हटा दिया है और स्पष्टता के लिए एक नई इंटीजर ऑब्जेक्ट के निर्माण को थोड़ा संशोधित किया है):

#define NSMALLPOSINTS   257 
    #define NSMALLNEGINTS   5 
    static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; 

    PyObject * 
    PyInt_FromLong(long ival) 
    { 
     register PyIntObject *v; 
     if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { 
      v = small_ints[ival + NSMALLNEGINTS]; 
      Py_INCREF(v); 
      return (PyObject *) v; 
     } 
     /* Inline PyObject_New */ 
     v = (PyIntObject *)Py_TYPE(v); 
     PyObject_INIT(v, &PyInt_Type); 
     v->ob_ival = ival; 
     return (PyObject *) v; 
    } 

तो अनिवार्य रूप से यह -5 256 करने के लिए समावेशी से सभी नंबरों को शामिल करते हुए एक पूर्व निर्धारित सरणी बनाता है और उन वस्तुओं यदि संभव हो तो (उनके संदर्भ Py_INCREF मैक्रो का उपयोग गिनती बढ़ रही है) का उपयोग करता है। यदि नहीं, तो यह एक नई नई PyInt_Type ऑब्जेक्ट बनाएगा, जिसे 1 की संदर्भ संख्या के साथ शुरू किया गया है।

रहस्य का मानना ​​है कि प्रत्येक संख्या में संदर्भ संख्या 3 (वास्तव में लगभग कोई नई वस्तु) क्यों होती है, जब आप पाइथन उत्पन्न करते हैं तो बाइट कोड देखते हैं। वर्चुअल मशीन एक वैल्यू स्टैक (फर्थ में थोड़ा सा) के साथ काम करती है, और प्रत्येक बार जब ऑब्जेक्ट को स्टैक स्टैक पर रखा जाता है तो यह संदर्भ गणना में वृद्धि करता है।

तो मुझे क्या संदेह हो रहा है यह है कि आपका कोड स्वयं आपके द्वारा देखे जाने वाले सभी 3 संदर्भ प्रदान कर रहा है, क्योंकि संख्याओं के लिए छोटे मूल्यों की सूची में नहीं, आपको एक अद्वितीय वस्तु मिलनी चाहिए। पहला संदर्भ संभावित रूप से कॉलफैक के कॉलर के लिए मूल्य स्टैक में होता है जब यह कॉल करता है; दूसरा getrefcount फ्रेम के लिए स्थानीय चर सूची में है; तीसरा गेटफ्रैंट फ्रेम में वैल्यू स्टैक पर होने की संभावना है, जबकि यह इसकी संदर्भ संख्या को देखता है।

यदि आप इस मुद्दे में आगे बढ़ना चाहते हैं तो एक उपयोगी टूल 'compile' कमांड, और 'डिस' कमांड (डिससेम्बल) है जो 'डी' मॉड्यूल में है, जो आपको एक साथ वास्तविक पढ़ने की अनुमति देगा बाइट कोड पाइथन कोड के किसी भी टुकड़े से उत्पन्न होता है, और आपको यह पता लगाने में मदद करनी चाहिए कि तीसरा संदर्भ कब और कहाँ बनाया जा रहा है।

छोटे मानों के लिए उच्च संदर्भ गणना के लिए, जब आप पाइथन शुरू करते हैं, तो यह स्वचालित रूप से संपूर्ण मानक लाइब्रेरी लोड करता है और आपके कोड को समझने से पहले बहुत सारे पायथन मॉड्यूल प्रारंभिक कोड चलाता है। ये मॉड्यूल अपनी प्रतियां कई छोटे पूर्णांक (और कोई भी ऑब्जेक्ट जो अद्वितीय भी नहीं है) रखते हैं।

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