नेस्टेड प्रयास में एक अपवाद को फिर से कैसे बढ़ाएं / ब्लॉक को छोड़कर?


107

मुझे पता है कि अगर मैं एक अपवाद को फिर से उठाना चाहता हूं, तो मैं raiseसंबंधित exceptब्लॉक में तर्क के बिना सरल उपयोग करता हूं । लेकिन जैसे नेस्टेड एक्सप्रेशन दिया

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # I'd like to raise the SomeError as if plan_B()
                 # didn't raise the AlsoFailsError

SomeErrorस्टैक ट्रेस को तोड़े बिना मैं फिर से कैसे उठा सकता हूं ? raiseअकेले इस मामले में और अधिक हाल ही में फिर से उठाना होगा AlsoFailsError। या मैं इस समस्या से बचने के लिए अपने कोड को कैसे रिफलेक्टर कर सकता हूं?


2
क्या आपने plan_Bकिसी अन्य फ़ंक्शन में डालने की कोशिश की है जो Trueसफलता पर लौटा है, और Falseअपवाद पर? तब बाहरी exceptब्लॉक बस हो सकता हैif not try_plan_B(): raise
आकर्षित मैकगॉवन

@DrewMcGowen दुर्भाग्य से अधिक यथार्थवादी मामला यह है कि यह एक फ़ंक्शन के अंदर है जो मनमाना वस्तुओं को स्वीकार करता है argऔर मैं कॉल करने की कोशिश करूंगा arg.plan_B()जो एक योजना बी प्रदान नहीं करने के AttributeErrorकारण हो सकता हैarg
टोबीस किंजलर

ट्रेसबैक मॉड्यूल पर एक नज़र डालें: docs.python.org/2/library/traceback.html#traceback-examples
Paco

@ पाको धन्यवाद, मैं (हालांकि एक जवाब पहले से ही एक सरल तरीका दिखाता है)
टोबियास किन्ज़लर

@DrewMcGowen मैंने आपकी टिप्पणी के आधार पर एक उत्तर लिखा है , जो कि user4815162342 के उत्तर की तुलना में कम पायथोनिक लगता है । लेकिन यह मेरी चाहत के कारण भी एक रिटर्न वैल्यू है और plan_Bअपवादों को बढ़ाने की इजाजत है
तोबियस किंजलर

जवाबों:


128

अजगर 3 के रूप में ट्रेसबैक अपवाद में रखा गया है, इसलिए एक साधारण raise e(ज्यादातर) सही काम करेगा:

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # or raise e from None - see below

उत्पादित ट्रेसबैक में एक अतिरिक्त नोटिस शामिल होगा जो कि SomeErrorसंभालते समय हुआ AlsoFailsError(क्योंकि raise eअंदर होने के कारण except AlsoFailsError)। यह भ्रामक है क्योंकि वास्तव में जो कुछ हुआ है वह चारों ओर का दूसरा तरीका है - हमने सामना किया AlsoFailsError, और इसे संभाला, जबकि इससे उबरने की कोशिश की गई थी SomeError। एक ट्रेसबैक प्राप्त करने के लिए जिसमें शामिल नहीं है AlsoFailsError, के raise eसाथ बदलें raise e from None

पायथन 2 में आप स्थानीय चर में अपवाद प्रकार, मान और ट्रेसबैक को संग्रहीत करेंगे और तीन-तर्क रूप का उपयोग करेंगेraise :

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb

बिल्कुल सही, यही तो मैं भी यहाँ पाया , धन्यवाद! हालांकि वहाँ सुझाव के raise self.exc_info[1], None, self.exc_info[2]बाद है self.exc_info = sys.exc_info()- [1]किसी कारण के लिए पहली स्थिति में
लाना

3
@TobiasKienzler raise t, None, tbअपवाद के मूल्य को खो देगा और आपको raiseइसे कम विशिष्ट (या बस गलत) अपवाद मान देते हुए, इसे फिर से टाइप करने के लिए मजबूर करेगा । उदाहरण के लिए, यदि उठाया गया अपवाद है KeyError("some-key"), तो यह KeyError()ट्रेसबैक से ठीक गायब कुंजी को फिर से बढ़ाएगा और छोड़ देगा।
user4815162342

3
@TobiasKienzler यह अभी भी संभव है कि पायथन 3 के रूप में व्यक्त किया जाए raise v.with_traceback(tb)। (आपकी टिप्पणी यह ​​भी कहती है, सिवाय इसके कि वह मूल्य को फिर से
बताने

2
इसके अलावा, sys.exc_info()पाइथन 2.0 (13 साल पहले जारी) से पहले एक स्थानीय चर में स्टोर नहीं करने की लाल चेतावनी , लेकिन आज हास्यास्पद है। आधुनिक पायथन चक्र कलेक्टर के बिना पास-बेकार होगा, क्योंकि प्रत्येक गैर-तुच्छ पायथन पुस्तकालय बिना ठहराव के चक्र बनाता है और उनके सही सफाई पर निर्भर करता है।
user4815162342

1
@ user4815162342 आप "अन्य से हुई त्रुटि" लिखकर "किसी अन्य त्रुटि हुई" नेस्टेड त्रुटि को मार सकते हैं।
मथायस उरलिचस

19

यहां तक ​​कि अगर स्वीकृत समाधान सही है, तो सिक्स लाइब्रेरी को इंगित करना अच्छा है, जिसका उपयोग करके पायथन 2 + 3 समाधान है six.reraise

छह। reraise ( exc_type , exc_value , exc_traceback = कोई नहीं)

संभवत: एक अलग ट्रेसबैक के साथ एक अपवाद को फिर से उठाएं। [...]

तो, आप लिख सकते हैं:

import six


try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        six.reraise(t, v, tb)

1
अच्छी बात - सिक्स की बात करें six.raise_fromतो आप इसका उपयोग भी कर सकते हैं यदि आप ऐसी जानकारी को शामिल करना चाहते हैं जो plan_B()विफल रही।
टोबियास किंजलर

1
@TobiasKienzler: मुझे लगता है कि यह एक अलग उपयोग है: six.raise_fromआप एक नया अपवाद बनाते हैं जो पिछले एक से जुड़ा हुआ है, आप फिर से नहीं बढ़ाते हैं , इसलिए ट्रेस बैक अलग है।
लॉरेंट लेपोरटी

1
मेरी बात बिल्कुल - अगर आप reraiseआप इंप्रेशन प्राप्त करके ही something()फेंक दिया SomeError, अगर आप raise_fromआप भी जानते हैं कि इस वजह से plan_B()मार डाला लेकिन फेंकने जा करने के लिए AlsoFailsError। तो यह usecase पर निर्भर करता है। मुझे लगता है कि raise_fromडिबगिंग को आसान बना देगा
टोबियास किंजलर

9

के अनुसार ड्रयू McGowen के सुझाव है, लेकिन एक सामान्य स्थिति (जहां एक वापसी मान की देखभाल sमौजूद है), यहाँ के लिए एक विकल्प है user4815162342 के जवाब :

try:
    s = something()
except SomeError as e:
    def wrapped_plan_B():
        try:
            return False, plan_B()
        except:
            return True, None
    failed, s = wrapped_plan_B()
    if failed:
        raise

1
इस दृष्टिकोण के बारे में अच्छी बात यह है कि यह पायथन 2 और 3 में अपरिवर्तित काम करता है
18:48 पर उपयोगकर्ता4815162342

2
@ user4815162342 अच्छा बिंदु :) हालांकि इस बीच पायथन 3 में मैं विचार करूंगा raise from, इसलिए स्टैक ट्रेस भी मुझे योजना को विफल करने देगा। जिसको पाइथन 2 में अनुकरण किया जा सकता है
टोबियास किंजलर

5

पायथन 3.5+ वैसे भी त्रुटि की ट्रेसबैक जानकारी संलग्न करता है, इसलिए इसे अलग से सहेजना आवश्यक नहीं है।

>>> def f():
...   try:
...     raise SyntaxError
...   except Exception as e:
...     err = e
...     try:
...       raise AttributeError
...     except Exception as e1:
...       raise err from None
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in f
  File "<stdin>", line 3, in f
SyntaxError: None
>>> 

2
सवाल एक और अपवाद के दौरान हो रहा है except। लेकिन आप सही हैं, जब मैं प्रतिस्थापित करता हूं err = e, तो कहता हूं raise AttributeError, आपको पहले SyntaxErrorस्टैक ट्रेस मिलता है , उसके बाद ए During handling of the above exception, another exception occurred:और AttributeErrorस्टैक ट्रेस मिलता है। यह जानना अच्छा है, हालांकि दुर्भाग्य से कोई 3.5+ स्थापित होने पर भरोसा नहीं कर सकता है। पुनश्च: ff verstehen nicht-Deutsche vermutlich nicht;)
टोबीस किंजलर

ठीक है, इसलिए मैंने एक और अपवाद जुटाने के लिए उदाहरण बदल दिया, जो (जैसा कि मूल प्रश्न के लिए पूछा गया) को अनदेखा कर दिया जाता है, जब मैं पहले एक को फिर से उठाता हूं।
मथायस उरलिचस

3
@TobiasKienzler 3.5+ (जिसे मैंने इसे बदल दिया) लगता है कि यह विश्व स्तर पर मान्यता प्राप्त प्रारूप है। डेन्कस्ट डू था? ;)
लिनसग

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.