2012-06-03 15 views
5

की संदर्भ गणना को समझना यह बेहतर समझने का प्रयास है कि संदर्भ गिनती पाइथन में कैसे काम करती है।कक्षा परिवर्तनीय

चलिए एक कक्षा बनाते हैं और इसे तुरंत चालू करते हैं। उदाहरण के संदर्भ गिनती होगी 1 (getrefcount प्रदर्शित करता है 2 क्योंकि यह की अपनी आंतरिक संरचना का संदर्भ उस वर्ग उदाहरण 1 द्वारा संदर्भ गिनती बढ़ रही है):

>>> from sys import getrefcount as grc 
>>> class A(): 
    def __init__(self): 
     self.x = 100000 


>>> a = A() 
>>> grc(a) 
2 

a के आंतरिक चर x है 2 संदर्भ:

>>> grc(a.x) 
3 

मुझे उम्मीद है कि इसे a और A की __init__ विधि द्वारा संदर्भित किया जाएगा। तब मैंने जांच करने का फैसला किया।

इसलिए मैंने __main__ नामस्थान में अस्थायी चर b बनाया है ताकि वे x चर का उपयोग कर सकें। यह 1 द्वारा रेफरी-संख्या में वृद्धि हुई यह 3 बन के लिए करने के लिए (उम्मीद के रूप में):

>>> del a 
>>> grc(b) 
3 

तो अब देखते हैं:

>>> b = a.x 
>>> grc(a.x) 
4 

तब मैं कक्षा उदाहरण और रेफरी गिनती 1 की कमी हुई हटाए गए 2 संदर्भ: एक b है और एक A (जैसा कि मैंने अपेक्षित था) है।

__main__ नामस्थान से A हटाकर मुझे लगता है कि गिनती 1 से फिर से घटने की उम्मीद है।

>>> del A 
>>> grc(b) 
3 

लेकिन यह नहीं होता है। A कोई संदर्भ नहीं है या इसके उदाहरण 100000 का संदर्भ दे सकते हैं, लेकिन फिर भी नामस्थान में b के अलावा किसी अन्य चीज़ द्वारा संदर्भित किया गया है।

तो, मेरा सवाल यह है कि b के अलावा संदर्भित क्या है?


BrenBarn सुझाव दिया है कि मैं एक नंबर जो कहीं न कहीं आंतरिक रूप से संग्रहीत किया जा सकता है के बजाय object() उपयोग करना चाहिए।

>>> class A(): 
    def __init__(self): 
     self.x = object() 


>>> a = A() 
>>> b = a.x 
>>> grc(a.x) 
3 
>>> del a 
>>> grc(b) 
2 

उदाहरण a हटाने के बाद b जो बहुत तार्किक है के द्वारा केवल एक संदर्भ बन रही थीं।

एकमात्र चीज जिसे समझने के लिए छोड़ दिया गया है, यह 100000 नंबर के साथ ऐसा नहीं है।

+0

मेरा अनुमान है, 'ए .__ dict__' करता है? –

+0

@JakobBowyer लेकिन जब मैं 'ए' हटा देता हूं, तो 'ए .__ dict__' कचरा एकत्र किया जाना चाहिए क्योंकि इसे किसी भी चीज़ (जैसा कि मैं समझता हूं) द्वारा संदर्भित नहीं किया जाता है। – ovgolovin

+1

यह उत्तर देखें: http://stackoverflow.com/questions/759740/unexpected-result-from-sys-getrefcount –

उत्तर

2

a.x पूर्णांक 10000 है। यह निरंतर की __init__() विधि से संबंधित कोड ऑब्जेक्ट द्वारा संदर्भित किया गया है।

>>> def f(): return 10000 
>>> f.__code__.co_consts 
(None, 10000) 

लाइन

del A 

केवल नाम A हट जाता है और A के संदर्भ गिनती कम हो जाती है: कोड वस्तुओं हमेशा कोड में सभी शाब्दिक स्थिरांक के संदर्भ शामिल हैं। पायथन 3.x (लेकिन 2.x में नहीं) में, कक्षाओं में अक्सर कुछ चक्रीय संदर्भ शामिल होते हैं, और इसलिए जब आप स्पष्ट रूप से कचरा कलेक्टर चलाते हैं तो केवल कचरा इकट्ठा होता है। और वास्तव में,

import gc 
gc.collect() 

का उपयोग कर del A के बाद b के संदर्भ गिनती में कमी करने के लिए नेतृत्व करता है।

+0

'__init__' को हटाने के लिए' ए' लीड को हटाना नहीं चाहिए क्योंकि इसे केवल 'ए' (जैसा कि मैं समझता हूं) द्वारा संदर्भित किया गया है? – ovgolovin

+0

ओह। मुझे अब दिख गया। '__main__' से हटाने से पहले' ए' की संदर्भ संख्या '4' है। तो यह हटाना केवल इसे '1' से कम कर देगा। अन्य वस्तुएं क्या हैं जो 'ए' का संदर्भ देती हैं? – ovgolovin

+0

@ovgolovin: मैंने अभी देखा है कि मैं आपके परिणामों को पुन: उत्पन्न नहीं कर सकता। मेरे लिए, क्लैस 'ए' वास्तव में * करता है * हटा दिया जाता है, और 'बी' * की संदर्भ संख्या * घट जाती है। एकमात्र अन्य चीज जिसे मैं सोच सकता हूं: इंटरैक्टिव दुभाषिया के '_' से सावधान रहें। संदेह में, इंटरैक्टिव दुभाषिया की बजाय एक स्क्रिप्ट में संदर्भ गणना के साथ बेहतर प्रयोग करें। –

2

यह संभावना है कि यह आपके परीक्षण मूल्य के रूप में पूर्णांक का उपयोग करने का एक आर्टिफैक्ट है। पाइथन कभी-कभी पूर्ण पुन: उपयोग के लिए पूर्णांक वस्तुओं को संग्रहीत करता है, क्योंकि वे अपरिवर्तनीय हैं। जब मैं self.x = object() का उपयोग करके अपना कोड चलाता हूं (जो हमेशा एक्स के लिए एक नई वस्तु बना देगा) मुझे अंत में grc(b)==2 मिलता है।

+0

आप सही हैं! 'ऑब्जेक्ट()' में '100000' को बदलकर 'getrefcount' पर लौटाई गई संख्याओं को बदल दिया गया। मैं सवाल अपडेट करूंगा। – ovgolovin

+0

@ovgolovin: बेशक यह करता है, क्योंकि कोड ऑब्जेक्ट केवल कोड में दिखाई देने वाले * स्थिरांक * को संदर्भित कर सकता है। यह किसी भी पूर्णांक ऑब्जेक्ट पुन: उपयोग के लिए पूरी तरह से असंबंधित है, हालांकि। बाद में पुन: उपयोग के लिए इंटीजर को यादृच्छिक रूप से कैश नहीं किया जाता है। पायथन केवल छोटे पूर्णांक (आमतौर पर -5 से 256 तक) का कैश रखता है, जो कि दुभाषिया प्रारंभ में बनाया जाता है और जब भी आवश्यक हो। अन्य सभी पूर्णांक मांग पर बनाए जाते हैं और कभी भी पुन: उपयोग नहीं किए जाते हैं। –

+0

डाउनवॉटिंग: हालांकि अवलोकन सटीक है, इस उत्तर में दिया गया कारण गलत है। –

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