2017-07-10 3 views
15

मैं जीआईएल के पीछे मूल व्यवहार और तर्क के बारे में व्याख्या करने के लिए सहकर्मियों के लिए एक प्रेजेंटेशन पर काम कर रहा हूं, और मुझे संदर्भ गिनती के त्वरित स्पष्टीकरण को एक साथ रखने के दौरान कुछ समझा नहीं जा सका। ऐसा प्रतीत होता है कि नए घोषित चर के चार संदर्भ हैं, जिनकी मैं अपेक्षा करता हूं। उदाहरण के लिए, निम्न कोड:पायथन में नव निर्मित चर के चारों की पुन: गणना क्यों होती है?

इस उत्पादन में
the_var = 'Hello World!' 
print('Var created: {} references'.format(sys.getrefcount(the_var))) 

परिणाम:

Var created: 4 references 

मैं पुष्टि है कि उत्पादन एक ही अगर मैं एक पूर्णांक> 100 (< 100 हैं प्रयोग किया जाता है पूर्व-निर्मित और एक बड़ी रेफ-गिनती है) या एक फ्लोट और यदि मैंने चर को फ़ंक्शन स्कोप या लूप में घोषित किया है। परिणाम वही था। व्यवहार 2.7.11 और 3.5.1 में भी समान लगता है।

मैंने sys.getrefcount को डीबग करने का प्रयास किया ताकि यह देखने के लिए कि यह अतिरिक्त संदर्भ बना रहा था, लेकिन फ़ंक्शन में कदम रखने में असमर्थ था (मुझे लगता है कि यह सी परत पर सीधे थंक है)।

मुझे पता है कि मैं इस पर कम से कम एक प्रश्न प्राप्त करने वाला हूं, और मैं वास्तव में आउटपुट द्वारा बहुत परेशान हूं। क्या कोई मुझे इस व्यवहार को समझा सकता है?

+0

क्या आप इसे सीधे पाइथन या आईपीथॉन खोल में टाइप कर रहे हैं? या इसे एक स्टैंडअलोन स्क्रिप्ट के रूप में चला रहे हैं? मुझे सादे पायथन खोल में 2 संदर्भ मिलते हैं। – Meitham

+0

जब मैं 2.7.13 में अपना कोड चलाता हूं तो मुझे 'Var बनाया गया: 2 संदर्भ' मिलता है। – Alex

+0

मैं इंटरैक्टिव मोड में 2 संदर्भ, और 3 स्क्रिप्ट के रूप में (कोड ऑब्जेक्ट के स्थिरांक से संदर्भ के लिए एक अतिरिक्त) की अपेक्षा करता हूं, लेकिन 4 नहीं। आपने एक और संदर्भ बनाने के लिए कुछ और किया होगा। – user2357112

उत्तर

13

कई परिदृश्य हैं जो एक अलग संदर्भ गणना प्रदान करेंगे। सबसे सरल आरईपीएल सांत्वना है:

>>> import sys 
>>> the_var = 'Hello World!' 
>>> print(sys.getrefcount(the_var)) 
2 

इस परिणाम को समझना बिल्कुल स्पष्ट है - स्थानीय ढेर में एक संदर्भ और एक अन्य अस्थायी/sys.getrefcount() समारोह (यहां तक ​​कि documentation इसके बारे में चेतावनी दी है करने के लिए स्थानीय है - The count returned is generally one higher than you might expect)। लेकिन जब आप एक स्टैंडअलोन स्क्रिप्ट के रूप में इसे चलाने:

import sys 

the_var = 'Hello World!' 
print(sys.getrefcount(the_var)) 
# 4 

के रूप में आप ध्यान दिया है, तो आप एक 4 मिलता है। तो क्या देता है? ठीक है, की सुविधा देता है की जांच ... वहाँ कचरा कलेक्टर करने के लिए एक बहुत ही उपयोगी इंटरफेस है - gc मॉड्यूल - तो अगर हम आरईपीएल कंसोल में इसे चलाने: वहाँ

>>> import gc 
>>> the_var = 'Hello World!' 
>>> gc.get_referrers(the_var) 
[{'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'the_var': 'Hello 
World!', 'gc': <module 'gc' (built-in)>, '__name__': '__main__', '__doc__': None}] 

कोई चमत्कार, - कि अनिवार्य रूप से सिर्फ वर्तमान नाम स्थान है (locals()) क्योंकि चर कहीं और मौजूद नहीं है। लेकिन क्या होता है जब हमारे द्वारा चलाए जा स्टैंडअलोन स्क्रिप्ट के रूप में:

import gc 
import pprint 

the_var = 'Hello World!' 
pprint.pprint(gc.get_referrers(the_var)) 

इस बाहर प्रिंट (YMMV, अपने अजगर संस्करण पर आधारित):

[['gc', 
    'pprint', 
    'the_var', 
    'Hello World!', 
    'pprint', 
    'pprint', 
    'gc', 
    'get_referrers', 
    'the_var'], 
(-1, None, 'Hello World!'), 
{'__builtins__': <module '__builtin__' (built-in)>, 
    '__doc__': None, 
    '__file__': 'test.py', 
    '__name__': '__main__', 
    '__package__': None, 
    'gc': <module 'gc' (built-in)>, 
    'pprint': <module 'pprint' from 'D:\Dev\Python\Py27-64\lib\pprint.pyc'>, 
    'the_var': 'Hello World!'}] 

पर्याप्त ज़रूर, हम सूची में दो और संदर्भ हो जैसे sys.getrefcount() ने हमें बताया, लेकिन वे क्या हैं? खैर, जब पाइथन दुभाषिया आपकी स्क्रिप्ट को पार्स कर रहा है तो इसे पहले compile पर बाइटकोड की आवश्यकता होती है - और जब यह करता है, तो यह सभी स्ट्रिंग्स को एक सूची में संग्रहीत करता है, क्योंकि यह आपके चर का भी उल्लेख करता है, इसे संदर्भ के रूप में घोषित किया जाता है।

दूसरी और गुप्त प्रविष्टि ((-1, None, 'Hello World!')) peep-hole optimizer से आता है और क्या वहां केवल एक्सेस (इस मामले में स्ट्रिंग संदर्भ) अनुकूलित है।

उन दोनों विशुद्ध रूप से अस्थायी और वैकल्पिक हैं - आरईपीएल सांत्वना संदर्भ जुदाई कर रही है ताकि आप इन संदर्भों को नहीं दिख रहा है, अगर आप अपने वर्तमान संदर्भ से अपने संकलन 'आउटसोर्स' के लिए गए थे:

import gc 
import pprint 

exec(compile("the_var = 'Hello World!'", "<string>", "exec")) 
pprint.pprint(gc.get_referrers(the_var)) 

आप 'प्राप्त डी:

import sys 

exec(compile("the_var = 'Hello World!'", "<string>", "exec")) 
print(sys.getrefcount(the_var)) 
# 2 
:

[{'__builtins__': <module '__builtin__' (built-in)>, 
    '__doc__': None, 
    '__file__': 'test.py', 
    '__name__': '__main__', 
    '__package__': None, 
    'gc': <module 'gc' (built-in)>, 
    'pprint': <module 'pprint' from 'D:\Dev\Python\Py27-64\lib\pprint.pyc'>, 
    'the_var': 'Hello World!'}] 

और आप sys.getreferencecount() के माध्यम से मूल का प्रयास करने के लिए वापस जाने के लिए थे, तो संदर्भ गिनती हो रही है पर

बस आरईपीएल कंसोल की तरह, और जैसा कि अपेक्षित था। Peep-hole अनुकूलन के कारण अतिरिक्त संदर्भ, क्योंकि यह जगह में होता है, तुरंत आपके संदर्भों की गणना करने से पहले कचरा संग्रह (gc.collect()) को मजबूर कर त्याग दिया जा सकता है।

हालांकि, संकलन के दौरान बनाई गई स्ट्रिंग सूची को तब तक रिलीज़ नहीं किया जा सकता जब तक कि पूरी फ़ाइल को पार्स और संकलित नहीं किया जाता है, यही कारण है कि यदि आप अपनी स्क्रिप्ट को किसी अन्य स्क्रिप्ट में आयात करना चाहते हैं और फिर the_var पर संदर्भों को गिनें आपको 4 के बजाय प्राप्त होगा जब आपने सोचा था कि यह आपको और भ्रमित नहीं कर सकता है;)

+0

मैं आपके द्वारा देखे जा रहे आउटपुट को पुन: उत्पन्न नहीं कर सकता - '4', या अतिरिक्त' gc.get_referrers() 'प्रविष्टियां। इस कोड को चलाने के लिए आप क्या उपयोग कर रहे हैं? – user2357112

+0

@ user2357112 - जब तक कि नवीनतम सीपीथन संस्करणों में कुछ बदलाव नहीं हुआ है, यह मानक 'पायथन test_script.py' निष्पादन के लिए डिफ़ॉल्ट व्यवहार होना चाहिए। बेशक, यदि आप अपनी स्क्रिप्ट को पीवाईसी में संकलित करते हैं और इसे चलाते हैं तो आपको '4' नहीं मिल रहा है - पूरे अतिरिक्त संदर्भ संकलन/अनुकूलन प्रक्रियाओं के कारण हैं। जब मैं समय प्राप्त करता हूं तो मैं नवीनतम सीपीथन स्रोत पर एक नज़र डालूंगा, लेकिन मुझे कल्पना नहीं है कि यह काफी बदल गया है। – zwer

+0

3.6 पर कोशिश कर रहा है (क्योंकि मैं भूल गया था कि विचार 3.5 पर था) '4' और सूची को पुन: उत्पन्न करता है, लेकिन' (-1, कोई नहीं, 'हैलो वर्ल्ड!') 'Tuple। – user2357112

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