2017-07-25 11 views
6

के बाद हटाए गए 'को छोड़कर' खंड में बाध्यकारी नाम पाइथन को नाम बाध्यकारी से कैसे रोक सकता है, जब वह नाम पकड़ा गया अपवाद बाध्य करने के लिए उपयोग किया जाता है? व्यवहार में यह परिवर्तन कब पाइथन में आया?क्लॉज

मैं दोनों अजगर 2 और अजगर 3 पर चलने के लिए कोड लिख रहा हूँ:

exc = None 
try: 
    1/0 
    text_template = "All fine!" 
except ZeroDivisionError as exc: 
    text_template = "Got exception: {exc.__class__.__name__}" 

print(text_template.format(exc=exc)) 

सूचना है कि exc स्पष्ट रूप से, स्वाभाविक है अपवाद हैंडलिंग से पहले तो अजगर जानता है कि यह बाहरी क्षेत्र में एक नाम है।

अजगर 2.7 पर, यह ठीक चलाता है और exc नाम में प्रयोग की जाने वाली बचता format कॉल ::

Got exception: ZeroDivisionError 

बढ़िया है, यह ठीक है कि मैं क्या चाहता हूँ: except खंड नाम बांधता और अपवाद ऑब्जेक्ट को संदर्भित करने के लिए मैं शेष नाम में उस नाम का उपयोग कर सकता हूं।

अजगर 3.5 पर, format कॉल के विफल होने की वजह से जाहिरा तौर पर exc बंधन हटा दी जाती है ::

Traceback (most recent call last): 
    File "<stdin>", line 8, in <module> 
NameError: name 'exc' is not defined 

क्यों exc बाहरी गुंजाइश से हटा बंधन है?except खंड के बाद का उपयोग करने के लिए बाध्यकारी नाम को विश्वसनीय रूप से संरक्षित करने के लिए का अर्थ है?

यह परिवर्तन पाइथन में कब आया, यह कहां दस्तावेज है?

क्या मुझे इसे पायथन 3 में एक बग के रूप में रिपोर्ट करने का अधिकार होगा?

+0

यह इरादा दिखता है: try/except कोड के लिए disassembly के भी स्पष्ट रूप से प्रलेखन द्वारा किए गए ऊपर बयान का समर्थन करता है। यदि आप 'छोड़कर' खंड के भीतर किसी अन्य चर के लिए 'exc' असाइन करते हैं तो आप इसे वहां पुनर्प्राप्त कर सकते हैं। संभावित डुप्लिकेट https://stackoverflow.com/questions/29268892/python-3-exception-deletes-variable-in-enclosing-scope-for- अज्ञात- मुझे पता था कि मुझे यह जवाब देना चाहिए था ... lol –

उत्तर

6

नहीं यह कोई बग नहीं है। जिस व्यवहार का आप अनुभव कर रहे हैं वह Python 3 documentation for the try/except statement में स्पष्ट रूप से और स्पष्ट रूप से परिभाषित किया गया है। इस व्यवहार के लिए कारण भी दिया जाता है:

जब एक अपवाद as target का उपयोग कर सौंपा गया है, यह except खंड के अंत में मंजूरी दे दी है। यह के रूप में यदि

except E as N: 
    foo 

except E as N: 
    try: 
     foo 
    finally: 
     del N 

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

कारण try/except ब्लॉक काम नहीं किया के दायरे से बाहर नाम की घोषणा है, क्योंकि आप as खंड में exc इस्तेमाल किया। तो वह नाम पायथन हटा दिया गया था।

ठीक as खंड में एक भिन्न नाम का उपयोग अपवाद करने के लिए बाध्य करने के लिए, और उसके बाद विभिन्न अपवाद नाम करने के लिए वैश्विक चर आवंटित करने के लिए है:

>>> exc_global = None 
>>> try: 
    1/0 
    text_template = "All fine!" 
except ZeroDivisionError as exc: 
    exc_global = exc 
    text_template = "Got exception: {exc.__class__.__name__}" 


>>> print(text_template.format(exc=exc_global)) 
Got exception: ZeroDivisionError 

एंथोनी Sottile के रूप में टिप्पणी में बताया गया है,

>>> code = """ 
try: 
    1/0 
    text_template = "All fine!" 
except ZeroDivisionError as exc: 
    text_template = "Got exception: {exc.__class__.__name__}" 
""" 
>>> from dis import dis 
>>> dis(code) 
    2   0 SETUP_EXCEPT   16 (to 18) 

    3   2 LOAD_CONST    0 (1) 
       4 LOAD_CONST    1 (0) 
       6 BINARY_TRUE_DIVIDE 
       8 POP_TOP 

    4   10 LOAD_CONST    2 ('All fine!') 
      12 STORE_NAME    0 (text_template) 
      14 POP_BLOCK 
      16 JUMP_FORWARD   38 (to 56) 

    5  >> 18 DUP_TOP 
      20 LOAD_NAME    1 (ZeroDivisionError) 
      22 COMPARE_OP    10 (exception match) 
      24 POP_JUMP_IF_FALSE  54 
      26 POP_TOP 
      28 STORE_NAME    2 (exc) 
      30 POP_TOP 
      32 SETUP_FINALLY   10 (to 44) 

    6   34 LOAD_CONST    3 ('Got exception: {exc.__class__.__name__}') 
      36 STORE_NAME    0 (text_template) 
      38 POP_BLOCK 
      40 POP_EXCEPT 
      42 LOAD_CONST    4 (None) 
     >> 44 LOAD_CONST    4 (None) 
      46 STORE_NAME    2 (exc) 
      48 DELETE_NAME    2 (exc) 
      50 END_FINALLY 
      52 JUMP_FORWARD    2 (to 56) 
     >> 54 END_FINALLY 
     >> 56 LOAD_CONST    4 (None) 
      58 RETURN_VALUE 
+0

इसका डिस्प्लेप्लोर भी बहुत स्पष्ट है (इसे एक फ़ंक्शन में फेंक दें, 'dis.dis (f)' चलाएं) - यह अनिवार्य रूप से 'exc = none; 'अंत में' ब्लॉक –

+1

@ एंथनीस्टाइल ग्रेट प्वाइंट के अंत में डेल एक्जी '। मैं इसे अपने उत्तर में जोड़ दूंगा। –