python - सीपीथॉन में पायथन बाइटकोड रन वास्तव में कितना है?




cpython python-internals (2)

मैं यह समझने की कोशिश कर रहा हूं कि पायथन कैसे काम करता है (क्योंकि मैं हर समय इसका उपयोग करता हूं!)। मेरी समझ से, जब आप अजगर स्क्रिप्टफ्रेम जैसी कोई चीज चलाते हैं, तो स्क्रिप्ट को बायटेकोड में बदल दिया जाता है और फिर इंटरप्रेटर / वीएम / सीपीथॉन-वास्तव में सिर्फ एक सी-प्रोग्राम है, जो अजगर बाइटकोड में पढ़ता है और तदनुसार कार्यक्रम को निष्पादित करता है।

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


Thg4535 का उत्तर पढ़ने के बाद, मुझे यकीन है कि आप ceval.c पर निम्नलिखित स्पष्टीकरण दिलचस्प पाएंगे: नमस्कार, ceval.c!

यह लेख यानिव अकिन द्वारा लिखी गई एक श्रृंखला का हिस्सा है जिसका मैं एक प्रशंसक: अजगर के इनार्ड्स की तरह हूं


यदि आप कुछ कोड (चाहे स्रोत कोड, एक लाइव फ़ंक्शन ऑब्जेक्ट या कोड ऑब्जेक्ट, आदि) का बायटेकोड देखना चाहते हैं, तो dis मॉड्यूल आपको बताएगा कि आपको वास्तव में क्या चाहिए। उदाहरण के लिए:

>>> dis.dis('i/3')
  1           0 LOAD_NAME                0 (i)
              3 LOAD_CONST               0 (3)
              6 BINARY_TRUE_DIVIDE
              7 RETURN_VALUE

dis डॉक्स समझाते हैं कि प्रत्येक बायटेकोड का क्या अर्थ है। उदाहरण के लिए, LOAD_NAME :

स्टैक पर co_names[namei] जुड़े मूल्य को co_names[namei]

इसे समझने के लिए, आपको यह जानना होगा कि co_names दुभाषिया एक आभासी स्टैक मशीन है , और क्या co_names है। inspect मॉड्यूल डॉक्स में सबसे महत्वपूर्ण आंतरिक वस्तुओं की सबसे महत्वपूर्ण विशेषताओं को दर्शाने वाली एक अच्छी तालिका है, इसलिए आप देख सकते हैं कि co_names code ऑब्जेक्ट्स की एक विशेषता है जो स्थानीय चर के नामों का एक समूह रखती है। दूसरे शब्दों में, LOAD_NAME 0 , LOAD_NAME 0 वें स्थानीय चर के साथ जुड़े मूल्य को धक्का देता है (और LOAD_NAME 0 रूप से यह ऊपर दिखता है और देखता है कि 0 वें स्थानीय चर का नाम 'i' ) है।

और यह देखने के लिए पर्याप्त है कि बाईटकोड का एक तार पर्याप्त नहीं है; दुभाषिया को कोड ऑब्जेक्ट की अन्य विशेषताओं की भी आवश्यकता होती है, और कुछ मामलों में फ़ंक्शन ऑब्जेक्ट की विशेषताएं (जो कि स्थानीय और ग्लोबल्स वातावरण से आती हैं) भी हैं।

inspect मॉड्यूल में कुछ उपकरण भी हैं जो लाइव कोड की जांच करने में आपकी मदद कर सकते हैं।

यह बहुत सारे दिलचस्प सामान का पता लगाने के लिए पर्याप्त है। उदाहरण के लिए, आप शायद यह जानते हैं कि पायथन संकलित समय पर यह पता लगाता है कि क्या फ़ंक्शन में एक चर स्थानीय, बंद, या वैश्विक है, इस आधार पर कि क्या आप इसे फ़ंक्शन बॉडी में कहीं भी असाइन करते हैं (और किसी भी nonlocal - global या global बयान पर); यदि आप तीन अलग-अलग कार्य लिखते हैं और उनके डिसएस्पेशन (और प्रासंगिक अन्य विशेषताओं) की तुलना करते हैं, तो आप बहुत आसानी से यह पता लगा सकते हैं कि यह क्या करना चाहिए।

(यहां जो थोड़ा मुश्किल है, वह क्लोजर सेल्स को समझ रहा है। वास्तव में इसे पाने के लिए, आपको 3 स्तरों के कार्यों की आवश्यकता होगी, यह देखने के लिए कि बीच की चीजों को अंतरतम एक के लिए कैसे आगे बढ़ाया जाए।)

यह समझने के लिए कि बायटेकोड की व्याख्या कैसे की जाती है और स्टैक मशीन कैसे काम करती है (सीपीथॉन में), आपको http://hg.python.org/cpython/file/3.3/Python/ceval.c#l790 स्रोत कोड को देखने की आवश्यकता है। Th435 और eyquem के उत्तर पहले से ही इसे कवर करते हैं।

यह समझना कि pyc फाइलें कैसे pyc जाती हैं केवल थोड़ी अधिक जानकारी लेती है। नेड बैचेल्ड के पास एक महान (यदि थोड़ा पुराना) ब्लॉग पोस्ट है, जिसे .pyc फ़ाइलों की संरचना कहा जाता है, जो सभी पेचीदा और अच्छी तरह से प्रलेखित भागों को कवर करता है। (ध्यान दें कि 3.3 में, आयात करने से संबंधित कुछ गोर कोड को C से पायथन में स्थानांतरित कर दिया गया है, जिससे इसका पालन करना आसान हो जाता है।) लेकिन मूल रूप से, यह सिर्फ कुछ हेडर जानकारी और मॉड्यूल का code ऑब्जेक्ट है, जिसे marshal द्वारा क्रमबद्ध किया marshal

यह समझने के लिए कि बाइटकोड को स्रोत कैसे संकलित किया जाता है, यह मजेदार हिस्सा है।

सीपीथॉन के कंपाइलर का डिज़ाइन बताता है कि सब कुछ कैसे काम करता है। ( पायथन डेवलपर गाइड के कुछ अन्य खंड भी उपयोगी हैं।)

शुरुआती सामानों के लिए- टोकेनाइजिंग और पार्सिंग - आप सिर्फ सही बिंदु पर कूदने के लिए मूल मॉड्यूल का उपयोग कर सकते हैं जहां वास्तविक संकलन करने का समय है। फिर compile.c देखें कि एएसटी कैसे compile.c में बदल जाता है।

मैक्रोज़ के माध्यम से काम करना थोड़ा कठिन हो सकता है, लेकिन एक बार जब आप इस विचार को समझ लेते हैं कि कंपाइलर एक स्टैक का उपयोग कैसे करता है ब्लॉक में उतरने के लिए, और यह कैसे उन compiler_addop और दोस्तों का उपयोग करता है जो वर्तमान स्तर पर बायोटेक्स का उत्सर्जन करते हैं, तो यह सब समझ में आता है।

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

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





python-internals