आपला पहिला Python ट्युटोरियल उघडणारे बहुतेक लोक थेट variables, loops आणि काहीतरी प्रत्यक्ष तयार करण्याकडे वळू इच्छितात. ही ओढ समजण्यासारखी आहे. पण जर तुम्ही थांबून Python नक्की काय आहे आणि त्याचा खालील मशीनशी (machine) कसा संबंध आहे हे समजून घेतले, तर तुम्ही भविष्यातील कोडमधील चुका (debug) खूप कमी गोंधळात शोधू शकाल. प्रोग्रामिंग भाषा सर्व सारख्या नसतात. त्या अमूर्ततेच्या (abstraction) वेगवेगळ्या स्तरांवर असतात, सोयीसाठी नियंत्रणाशी (control) वेगवेगळ्या प्रकारे तडजोड करतात आणि प्रोसेसरपर्यंत पोहोचण्यासाठी वेगवेगळ्या मार्गांचा वापर करतात. Python या परिसंस्थेत (ecosystem) एका अतिशय विशिष्ट ठिकाणी आहे. ते स्थान समजून घेणे ही प्रोग्रामिंग शिकण्याच्या दिशेने पहिली खरी पायरी आहे.

भाषेचा श्रेणीक्रम: Python कुठे आहे

हार्डवेअरच्या (hardware) जवळ असल्याच्या आधारावर प्रोग्रामिंग भाषांचे प्रामुख्याने तीन प्रकार पडतात.

High-level languages सिलिकॉनपासून सर्वात दूर असतात. Python येथे Java आणि JavaScript सोबत राहते. या भाषा मानवी भाषेसारखी दिसणारी सिंटॅक्स (syntax) वापरतात. मेमरी ॲड्रेस (memory addresses) आणि बायनरी सूचनांशी (binary instructions) झुंजण्याऐवजी तुम्ही user_count = 5 किंवा print("Hello") असे लिहिता. कारण त्या CPU, मेमरी मॅनेजमेंट आणि चिपसेटमधील फरकांचा तपशील लपवतात (abstract), त्यामुळे तोच हाय-लेव्हल कोड फारशा किंवा कोणत्याही बदलाशिवाय Mac, Windows PC किंवा Linux सर्व्हरवर चालू शकतो.

ही पोर्टेबिलिटी (portability) एका किमतीवर येते. हाय-लेव्हल भाषांना एका ट्रान्सलेटरची (translator) गरज असते. त्या थेट प्रोसेसरवर चालू शकत नाहीत. तुमच्या वाचनीय कोड आणि मशीनचे इलेक्ट्रिकल सिग्नल यांच्यातील अंतर भरून काढण्यासाठी तुम्हाला कंपायलर (compiler) किंवा इंटरप्रिटर (interpreter) आवश्यक असतो. याचा फायदा म्हणजे विकासाचा वेग (speed of development). तुम्ही थेट हार्डवेअर नियंत्रणाचा त्याग करता जेणेकरून तुम्ही पहिल्या दिवसापासून उपयुक्त प्रोग्राम लिहू शकाल.

Low-level languages अगदी विरुद्ध टोकाला असतात. हे प्रामुख्याने मशीन कोड (machine code) असतात — एक आणि शून्य (ones and zeros) यांच्या अशा कच्च्या मालिका ज्या प्रोसेसर थेट समजतो. मशीन कोड लिहिणे म्हणजे स्वतः चिपप्रमाणे विचार करणे होय. कोणता मेमरी ॲड्रेस ॲक्सेस केला जावा आणि कोणता CPU रजिस्टर विशिष्ट व्हॅल्यू साठवेल, हे तुम्ही स्वतः ठरवता. हार्डवेअर कोणत्याही ट्रान्सलेशन ओव्हरहेडशिवाय (translation overhead) त्वरित आज्ञा पाळते.

याची किंमत म्हणजे प्रचंड जटिलता (complexity). एका साध्या बेरजेसाठी देखील अनेक रजिस्टर्सचे मॅन्युअल मॅनेजमेंट करावे लागू शकते. एक चुकीचा बिट संपूर्ण सिस्टम क्रॅश करू शकतो आणि कोणताही उपयुक्त एरर मेसेज (error message) देखील मिळत नाही. शुद्ध मशीन कोड आता जवळजवळ कधीही हाताने लिहिला जात नाही, परंतु प्रत्येक प्रोग्रामला बोलवी लागणारी ती अंतिम भाषा आहे.

Assembly languages मधल्या एका अरुंद भागामध्ये येतात. त्या बायनरी सूचनांच्या जागी 'मेमोनिक्स' (mnemonics) नावाचे मानवाला वाचता येतील असे छोटे सिम्बॉल्स वापरतात. एक आणि शून्य यांच्या मालिकेऐवजी, तुम्ही डेटा हलवण्यासाठी MOV किंवा बेरीज करण्यासाठी ADD असे लिहू शकता. हे सिम्बॉल्स कच्च्या बायनरीपेक्षा लक्षात ठेवण्यास सोपे आहेत, परंतु ते विशिष्ट प्रोसेसर आर्किटेक्चरशी (processor architecture) घट्टपणे जोडलेले असतात. Intel x86 चिपसाठी लिहिलेला असेंब्ली प्रोग्राम ARM प्रोसेसरवर चालणार नाही.

एक असेंबलर (assembler) या मेमोनिक्सचे मशीन कोडमध्ये रूपांतर करतो. असेंब्ली प्रोग्रामर्सना Python पेक्षा कितीतरी जास्त नियंत्रण देते, परंतु त्यासाठी प्रोसेसरच्या अंतर्गत कार्यपद्धतीचे सखोल ज्ञान आवश्यक असते. हे बायनरीपेक्षा मानवी विचारांच्या जवळ आहे, तरीही ते प्रोसेसरची मूळ भाषा (native dialect) बोलते.

कोड कृतीमध्ये कसा रूपांतरित होतो

प्रत्येक प्रोग्रामला शेवटी मशीन सूचनांमध्ये (machine instructions) रूपांतरित व्हावे लागते. सोर्स कोडपासून चालणाऱ्या ॲप्लिकेशनपर्यंतचा मार्ग दोनपैकी एका धोरणाचे अनुसरण करतो.

एक compiler तुमच्या संपूर्ण कोडबेसचे एकाच वेळी भाषांतर करतो. जर तुम्ही त्याला शंभर ओळींची फाईल दिली, तर ते काहीही चालवण्याचा प्रयत्न करण्यापूर्वी सर्व शंभर ओळी वाचते आणि त्यांचे विश्लेषण करते. ते संपूर्ण प्रोग्राममध्ये सिंटॅक्स एरर्स (syntax errors) शोधते. पन्नाव्या ओळीवर टायपिंगची चूक सापडली? कंपायलर थांबतो, समस्येची नोंद करतो आणि जोपर्यंत तुम्ही ती सुधारत नाही तोपर्यंत चालण्यायोग्य प्रोग्राम तयार करण्यास नकार देतो.

C आणि C++ सारख्या भाषा या दृष्टिकोनाचा वापर करतात. याचे परिणाम स्वरूप सहसा कच्च्या वेगासाठी (raw speed) ऑप्टिमाइझ केलेली एक स्वतंत्र एक्झिक्युटेबल फाईल (executable file) मिळते. कंपायलर सुरुवातीलाच संपूर्ण कोडबेसची बारकाईने तपासणी करत असल्यामुळे, प्रोग्राम सुरू होण्यापूर्वीच तो एररच्या अनेक श्रेणी शोधून काढतो. यात अडथळा म्हणजे वेळ. एडिट-कंपाईल-रन (edit-compile-run) चक्रासाठी वेळ लागतो. एक ओळ बदलली तरी संपूर्ण प्रोजेक्ट पुन्हा तयार होण्याची (rebuild) तुम्हाला वाट पाहावी लागू शकते.

एक interpreter पूर्णपणे वेगळा दृष्टिकोन घेतो. ते तुमचा कोड ओळ दर ओळ वाचते, आणि प्रत्येक विधान वाचतानाच त्याचे भाषांतर करून ते कार्यान्वित करते. ते संपूर्ण फाईलची तपासणी होईपर्यंत वाट पाहत नाही. Python REPL मध्ये एखादी कमांड टाईप करा, Enter दाबा आणि इंटरप्रिटर त्या एका ओळीवर प्रक्रिया करतो, त्याचे सूचनांमध्ये रूपांतर करतो आणि लगेच ते कार्यान्वित करतो.

यामुळे डीबगिंगचा (debugging) अनुभव बदलतो. इंटरप्रिटरसोबत, त्रुटी (errors) तेव्हाच समोर येतात जेव्हा इंटरप्रिटर त्या समस्याग्रस्त ओळीपर्यंत पोहोचतो, त्याआधी नाही. तुमचा प्रोग्राम ऐंशी ओळींपर्यंत अगदी व्यवस्थित चालू शकतो आणि त्यानंतर एक्क्याऐंशीव्या ओळीवर क्रॅश (crash) होऊ शकतो. ही तत्परता इंटरप्रिटरला शिकण्यासाठी अधिक सोपे बनवते. तुम्ही प्रयोग करता, निकाल पाहता आणि रिअल-टाइममध्ये बदल करता. पायथनची मानक अंमलबजावणी (standard implementation), CPython, प्रत्यक्षात एक हायब्रिड मॉडेल वापरते: ते तुमच्या सोर्स कोडचे बाइटकोडमध्ये (bytecode) रूपांतर करते आणि नंतर व्हर्च्युअल मशीनद्वारे तो बाइटकोड कार्यान्वित करते. जरी अंतर्गत एक ट्रान्सलेशन स्टेप असली, तरी त्याचा अनुभव परस्परसंवादी (interactive) आणि ओळ-दर-ओळ (line-by-line) असा वाटतो.

पायथनला स्क्रिप्टिंग लँग्वेज का म्हटले जाते

पायथनचे वर्णन अनेकदा स्क्रिप्टिंग लँग्वेज म्हणून केले जाते. हे लेबल त्याच्या उगमस्थानाचा आणि सामान्य वापराच्या पद्धतींचा संदर्भ देते. तुम्ही एक छोटी फाईल — एक स्क्रिप्ट — लिहिता जी एखादे कार्य स्वयंचलित करते, मजकुरात बदल करते किंवा वेगवेगळ्या प्रोग्राम्सना एकत्र जोडते आणि तुम्ही ती थेट कार्यान्वित करता. इंटरप्रिटर तात्काळ (on the fly) भाषांतर हाताळतो. व्यवस्थापित करण्यासाठी कोणतीही वेगळी कंपायलेशन स्टेप नसते आणि ट्रॅक करण्यासाठी कोणतेही बिल्ड आर्टिफॅक्ट्स (build artifacts) नसतात.

स्क्रिप्टिंग लँग्वेज आणि जनरल-पर्पज प्रोग्रामिंग लँग्वेज यांमधील रेषा आता बऱ्याच अंशी पुसट झाली आहे. पायथन आता प्रचंड वेब ॲप्लिकेशन्स, डेटा सायन्स पाइपलाइन्स आणि मशीन लर्निंग सिस्टम्सना सक्षम करते. तरीही, मूळ संकल्पना कायम आहे. तुम्ही बिल्ड सिस्टम व्यवस्थापित करण्याऐवजी समस्या सोडवण्यावर लक्ष केंद्रित करता. तुम्ही विचारताच इंटरप्रिटर तुमच्या सूचना कार्यान्वित करण्यासाठी तयार असतो.

भक्कम पाया निर्माण करणे

हे फरक केवळ शैक्षणिक माहिती नसून, पायथन लिहिण्याच्या तुमच्या पहिल्या आठवड्यात तुम्हाला येणाऱ्या वर्तणुकीचे (behavior) स्पष्टीकरण देतात. जेव्हा पायथन एक्झिक्यूशन दरम्यान SyntaxError दर्शवते, तेव्हा तुम्हाला आता समजते की इंटरप्रिटर अशा ओळीवर पोहोचला आहे ज्याचे भाषांतर तो करू शकला नाही. जेव्हा तुम्ही वाचता की काही कामांसाठी पायथन C पेक्षा संथ आहे, तेव्हा तुम्हाला इंटरप्रिटेशनचा ओव्हरहेड (overhead) आणि हाय-लेव्हल ॲब्स्ट्रॅक्शन (high-level abstraction) समजते. जेव्हा तुम्हाला तुमच्या स्क्रिप्ट्ससोबत .pyc फाईल्स दिसतात, तेव्हा तुम्हाला समजते की पायथन कंपाईल केलेला बाइटकोड कॅश (cache) करत आहे जेणेकरून प्रत्येक वेळी तुमच्या टेक्स्ट फाईलचे पुन्हा भाषांतर करावे लागू नये.

लँग्वेज हायरार्कीमध्ये (language hierarchy) पायथनचे स्थान कुठे आहे हे समजल्यामुळे तुम्हाला नंतर योग्य साधन निवडण्यास मदत होते. जिथे प्रत्येक CPU सायकल महत्त्वाची आहे असा डिव्हाइस ड्रायव्हर लिहायचा आहे? तुम्ही बहुधा C किंवा असेंब्ली (assembly) वापराल. एका दुपारी CSV फाईल प्रोसेस करायची आहे किंवा वेब API बनवायचा आहे? पायथनचा इंटरप्रिटर आणि वाचनीय सिंटॅक्स (syntax) नेमक्या याच कामासाठी बनवला गेला आहे.

मुख्य निष्कर्ष

पायथनची ताकद त्याच्या स्थानामुळे आहे. ते हार्डवेअरच्या खूप वर असते, ज्याचे भाषांतर अशा इंटरप्रिटरद्वारे केले जाते जो मशीनच्या वेगापेक्षा प्रोग्रामरच्या वेगाला अधिक महत्त्व देतो. हे पार्श्वभूमी ज्ञान नसतानाही तुम्ही सिंटॅक्स शिकू शकता, परंतु जोपर्यंत तुम्हाला अंतर्गत यंत्रणा समजली नाही, तोपर्यंत तुम्ही हुशारीने डीबगिंग किंवा अंतर्ज्ञानाने ऑप्टिमायझेशन करू शकणार नाही. या मूलभूत गोष्टींपासून सुरुवात करा. जेव्हा तुम्ही तुमचा पहिला खरा प्रोग्राम लिहाल, तेव्हा तुम्ही फक्त कमांड्स टाईप करणार नाही, तर त्या नेमक्या कशा प्रकारे मशीनपर्यंत पोहोचतात हे तुम्हाला माहित असेल.