पाइथन थोड़ा अजीब है कि यह विभिन्न scopes के लिए एक शब्दकोश में सब कुछ रखता है। मूल a, b, c ऊपरवाले के दायरे में हैं और इसलिए उस ऊपरवाले शब्दकोश में। फ़ंक्शन का अपना शब्दकोश है। जब आप पहुंचते हैं print(a)
और print(b)
बयान देते हैं, तो शब्दकोश में उस नाम से कुछ भी नहीं होता है, इसलिए पायथन सूची को देखता है और उन्हें वैश्विक शब्दकोश में पाता है।
अब, हम c+=1
, जो, के बराबर है c=c+1
। जब पायथन उस रेखा को स्कैन करता है, तो वह कहता है, "अ, सी नाम का एक चर है, मैं इसे अपने स्थानीय दायरे के शब्दकोश में डालूंगा।" फिर जब यह असाइनमेंट के दाहिने हाथ की तरफ सी के लिए सी के लिए एक मूल्य की तलाश में जाता है, तो यह सी नाम के अपने स्थानीय चर को ढूंढता है , जिसका अभी तक कोई मूल्य नहीं है, और इसलिए त्रुटि फेंकता है।
global c
ऊपर उल्लिखित कथन बस पार्सर को बताता है कि यह c
वैश्विक दायरे से उपयोग करता है और इसलिए इसे नए की आवश्यकता नहीं है।
इसका कारण यह है कि लाइन पर एक मुद्दा है जो ऐसा करता है क्योंकि यह प्रभावी रूप से कोड उत्पन्न करने से पहले नामों की तलाश कर रहा है, और इसलिए कुछ अर्थों में ऐसा नहीं लगता कि यह वास्तव में अभी तक उस लाइन को कर रहा है। मेरा तर्क है कि एक प्रयोज्य बग है, लेकिन यह आम तौर पर एक संकलक के संदेशों को बहुत गंभीरता से नहीं लेने के लिए सीखना एक अच्छा अभ्यास है ।
यदि यह कोई आराम है, तो मैंने शायद एक दिन खुदाई और इसी मुद्दे के साथ प्रयोग करने से पहले मैंने पाया कि गुइडो ने कुछ शब्दकोशों के बारे में लिखा था, जो सब कुछ समझाया।
अपडेट करें, टिप्पणियां देखें:
यह कोड को दो बार स्कैन नहीं करता है, लेकिन यह कोड को दो चरणों में स्कैन करता है, लेक्सिंग और पार्सिंग।
विचार करें कि कोड की इस पंक्ति का पार्स कैसे काम करता है। लेक्सर स्रोत पाठ को पढ़ता है और इसे व्याकरण के "सबसे छोटे घटकों" लेक्समेस में तोड़ता है। तो जब यह लाइन मारता है
c+=1
यह इसे कुछ इस तरह से तोड़ता है
SYMBOL(c) OPERATOR(+=) DIGIT(1)
पार्सर अंततः इसे एक पार्स ट्री में बनाना चाहता है और इसे निष्पादित करता है, लेकिन चूंकि यह एक असाइनमेंट है, ऐसा करने से पहले, यह स्थानीय शब्दकोश में सी नाम की तलाश करता है, इसे नहीं देखता है और इसे शब्दकोश में सम्मिलित करता है, अंकन करता है यह असंवैधानिक है। पूरी तरह से संकलित भाषा में, यह सिर्फ प्रतीक तालिका में जाएगा और पार्स की प्रतीक्षा करेगा, लेकिन चूंकि यह WON'T के पास एक दूसरे पास की लक्जरी नहीं है, इसलिए बाद में जीवन को आसान बनाने के लिए लेक्सर थोड़ा अतिरिक्त काम करता है। केवल, फिर यह OPERATOR देखता है, देखता है कि नियम कहते हैं "यदि आपके पास एक ऑपरेटर है = बाएं हाथ की तरफ प्रारंभिक किया गया है" और कहता है "वाह!"
यहाँ मुद्दा यह है कि यह वास्तव में अभी तक लाइन के पार्स को शुरू नहीं किया है । यह सभी वास्तविक पार्स के लिए तैयारी की तरह हो रहा है, इसलिए लाइन काउंटर अगली पंक्ति के लिए उन्नत नहीं है। इस प्रकार जब यह त्रुटि को इंगित करता है, तो यह अभी भी पिछली पंक्ति पर सोचता है।
जैसा कि मैं कहता हूं, आप तर्क कर सकते हैं कि यह एक बेकार बग है, लेकिन यह वास्तव में एक काफी सामान्य बात है। कुछ कंपाइलर इसके बारे में अधिक ईमानदार होते हैं और कहते हैं "एरर ऑन या अराउंड XXX", लेकिन यह नहीं है।