2017-02-25 11 views
7
def fun(): 
    if False: 
     x=3 
    print(locals()) 
    print(x) 
fun() 

उत्पादन और त्रुटि संदेश संकलन:अजगर स्थानीय चर सिद्धांत

{} 
--------------------------------------------------------------------------- 
UnboundLocalError       Traceback (most recent call last) 
<ipython-input-57-d9deb3063ae1> in <module>() 
     4  print(locals()) 
     5  print(x) 
----> 6 fun() 

<ipython-input-57-d9deb3063ae1> in fun() 
     3   x=3 
     4  print(locals()) 
----> 5  print(x) 
     6 fun() 

UnboundLocalError: local variable 'x' referenced before assignment 

मैं सोच रहा हूँ कैसे अजगर दुभाषिया काम करता है। ध्यान दें कि x = 3 बिल्कुल नहीं चलता है, और इसे स्थानीय चर के रूप में नहीं माना जाना चाहिए, जिसका अर्थ है कि त्रुटि "नाम 'x' परिभाषित नहीं की जाएगी"। लेकिन कोड और त्रुटि संदेश में देखो, यह मामला नहीं है। क्या कोई इस स्थिति के पीछे अजगर दुभाषिया के संकलन के तंत्र सिद्धांत को समझा सकता है?

+0

संभावित डुप्लिकेट http://stackoverflow.com/q/7969949/3758972 –

+0

यह प्रासंगिक हो सकता है: [स्कोपिंग नियमों का संक्षिप्त विवरण] (http://stackoverflow.com/questions/291978/short-description-of- स्कोपिंग-नियम) –

+0

यदि नीचे दिए गए उत्तरों में से कोई एक आपकी समस्या को हल करता है, तो आपको इसे स्वीकार करना चाहिए (उचित उत्तर के बगल में स्थित चेक मार्क पर क्लिक करें)। यह दो चीजें करता है। यह सभी को यह बताता है कि आपकी समस्या को आपकी संतुष्टि के लिए हल किया गया है, और यह वह व्यक्ति देता है जो सहायता के लिए आपको क्रेडिट करने में मदद करता है। एक पूर्ण स्पष्टीकरण के लिए [यहां] (http://meta.stackexchange.com/a/5235) देखें। –

उत्तर

4

तो, अजगर हमेशा एक नाम प्रत्येक कार्य में में से एक स्थानीय, गैर स्थानीय या वैश्विक होने के रूप में वर्गीकृत होगा। ये नाम स्कोप अनन्य हैं; प्रत्येक फ़ंक्शन के भीतर (नेस्टेड फ़ंक्शंस में नामों का अपना नामकरण क्षेत्र होता है), प्रत्येक नाम इन श्रेणियों में से केवल एक से संबंधित हो सकता है।

जब अजगर इस कोड को संकलित करता है:

def fun(): 
    if False: 
     x=3 

उस में के रूप में एक सार वाक्य रचना पेड़ में परिणाम होगा:

FunctionDef(
    name='fun', 
    args=arguments(...), b 
    body=[ 
     If(test=NameConstant(value=False), 
      body=[ 
       Assign(targets=[Name(id='x', ctx=Store())], value=Num(n=3)) 
      ], 
      orelse=[]) 
    ] 
) 

(कुछ सामान संक्षिप्तता के लिए छोड़े गए)। अब, जब यह सार वाक्यविन्यास पेड़ कोड में संकलित किया जाता है, तो पायथन सभी नाम नोड्स पर स्कैन करेगा। अगर वहाँ है किसी भी Name नोड्स, ctx=Store() साथ, उस नाम जब तक एक ही समारोह परिभाषा के दायरे में साथ global (अर्थात global x) या nonlocal (nonlocal x) बयान अधिरोहित, enclosing FunctionDef यदि कोई हो को स्थानीय माना जाता है।

ctx=Store() मुख्य रूप से तब होगा जब प्रश्न में नाम असाइनमेंट के बाईं ओर उपयोग किया जाता है, या for लूप में पुनरावृत्ति चर के रूप में होता है।

अब, जब अजगर बाईटकोड को यह संकलित है, जिसके परिणामस्वरूप बाईटकोड

>>> dis.dis(fun) 
    4   0 LOAD_GLOBAL    0 (print) 
       3 LOAD_FAST    0 (x) 
       6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
       9 POP_TOP 
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE 

है अनुकूलक if बयान पूरी तरह से हटा; हालांकि, चर को पहले से ही फ़ंक्शन में स्थानीय चिह्नित किया गया था, LOAD_FAST का उपयोग x के लिए किया जाता है, जिसके परिणामस्वरूप xस्थानीय चर, और स्थानीय चर केवल एक्सेस किया जा सकता है। चूंकि x सेट नहीं किया गया है, UnboundLocalError फेंक दिया गया है। दूसरी तरफ print नाम कभी सौंपा नहीं गया था, और इस प्रकार इस फ़ंक्शन के भीतर वैश्विक नाम माना जाता है, इसलिए इसका मान LOAD_GLOBAL से भरा हुआ है।

3

तथ्य यह है कि x = 3 पहुंच योग्य नहीं है अप्रासंगिक है। फ़ंक्शन इसे असाइन करता है, इसलिए यह एक स्थानीय नाम होना चाहिए।

ध्यान रखें कि निष्पादन शुरू होने से पहले पूरी फ़ाइल संकलित की जाती है, लेकिन फ़ंक्शन को निष्पादन चरण के दौरान परिभाषित किया जाता है, जब संकलित फ़ंक्शन परिभाषा ब्लॉक निष्पादित किया जाता है, फ़ंक्शन ऑब्जेक्ट बनाते हैं।

एक परिष्कृत ऑप्टिमाइज़र पहुंचने योग्य कोड को खत्म कर सकता है, लेकिन सीपीथन का ऑप्टिमाइज़र स्मार्ट नहीं है - यह केवल बहुत ही सरल कीहोल अनुकूलन करता है।

पायथन इंटर्नल्स पर गहराई से देखने के लिए, अस्थिर और डी मॉड्यूल पर एक नज़र डालें।

+0

क्या आप कृपया थोड़ा और विस्तार कर सकते हैं। –

+0

'तथ्य यह है कि x = 3 पहुंच योग्य नहीं है अप्रासंगिक है। फ़ंक्शन इसे असाइन करता है, इसलिए यह एक स्थानीय नाम होना चाहिए। इसलिए आप कह रहे हैं कि 'स्थानीय() 'x नहीं दिखाएगा क्योंकि यह केवल एक परिभाषित नाम है और मूल्य को असाइन नहीं किया गया है? (या ऐसा कुछ) –

+0

@vikash क्योंकि चर बनने तक अस्तित्व में नहीं है। और चूंकि असाइनमेंट कभी निष्पादित नहीं होता है जो कभी नहीं होता है। –

4

किसी फ़ंक्शन में उपयोग किए गए नाम में पूरे फ़ंक्शन बॉडी के लिए केवल एक गुंजाइश हो सकती है। दायरा संकलन समय पर निर्धारित होता है (जब फ़ंक्शन चलाया जाता है)।

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

एक विशेष मामला वह जगह है जहां एक फ़ंक्शन के शरीर में एक नाम असाइन किया जाता है, और पहले फ़ंक्शन के भीतर परिभाषित किसी अन्य फ़ंक्शन से एक्सेस किया जाता है। इस तरह के एक चर को विशेष closure सेल में रखा जाएगा जो कार्यों के बीच साझा किया जाएगा। बाहरी फ़ंक्शन वैरिएबल को स्थानीय की तरह व्यवहार करेगा, जबकि आंतरिक फ़ंक्शन केवल उसमें असाइन कर सकता है यदि उसके नाम के लिए nonlocal कथन है।

x = 1 
def foo(): 
    print(x) # you might expect this to print the global x, but it raises an exception 
    x = 2  # this assignment makes the compiler treat the name x as local to the function 

foo समारोह में:

def counter(): 
    val = 0 
    def helper(): 
     nonlocal val 
     val += 1 
     return val 
    return helper 

मुद्दा आप देख रहे हैं के अलावा, वहाँ गुंजाइश भ्रम का एक और प्रकार है कि आप देख सकते हैं: यहाँ एक बंद का एक उदाहरण है और एक nonlocal बयान है x नाम स्थानीय स्थान पर माना जाता है, भले ही print कॉल स्थानीय नामस्थान में असाइन किए जाने से पहले इसका उपयोग करने का प्रयास करता है।

+1

बंद करने का उल्लेख करने के लिए धन्यवाद। –

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