मैं पायथन में एक कस्टम संदेश के साथ उसी अपवाद को कैसे बढ़ाऊं?


145

मेरे पास tryमेरे कोड में यह ब्लॉक है:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise ValueError(errmsg)

कड़े शब्दों में, मैं वास्तव में एक और उठा रहा हूं ValueError, न कि ValueErrorफेंका हुआ do_something...(), जिसे errइस मामले में संदर्भित किया गया है। मैं एक कस्टम संदेश कैसे संलग्न करूं err? मैं निम्नलिखित कोड की कोशिश लेकिन कारण करने में विफल रहता errहै, एक ValueError उदाहरण , प्रतिदेय नहीं किया जा रहा:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)

13
@ हमिश, अतिरिक्त जानकारी संलग्न करना और डिबगिंग के समय अपवादों को फिर से बढ़ाना बहुत मददगार हो सकता है।
जोहान लुंडबर्ग

@ जोहान बिल्कुल - और यही एक स्टैकट्रेस है। यह समझ में नहीं आ रहा है कि आप नई त्रुटि को बढ़ाने के बजाय मौजूदा त्रुटि संदेश को क्यों संपादित करेंगे।
हमीश

@Hamish। ज़रूर लेकिन आप अन्य सामान जोड़ सकते हैं। आपके प्रश्न के लिए, मेरे उत्तर पर नज़र डालें और यूनिकोड डब्लूडब्लूयोर के उदाहरण देखें। यदि आपके पास इस पर कोई टिप्पणी है तो शायद मेरे जवाब पर टिप्पणी करें।
जोहान लुंडबर्ग


1
@ यह 2020 है और अजगर 3 हर जगह है। बेन के उत्तर के स्वीकृत उत्तर को क्यों न बदलें :-)
mit

जवाबों:


88

अपडेट: पायथन 3 के लिए, बेन के जवाब की जांच करें


किसी संदेश को वर्तमान अपवाद से जोड़ना और उसे फिर से बढ़ाना: (बाहरी कोशिश / सिवाय इसके कि प्रभाव दिखाना है)

अजगर के लिए 2. x जहाँ x> = 6:

try:
    try:
      raise ValueError  # something bad...
    except ValueError as err:
      err.message=err.message+" hello"
      raise              # re-raise current exception
except ValueError as e:
    print(" got error of type "+ str(type(e))+" with message " +e.message)

यह भी सही काम करेंगे अगर errहै व्युत्पन्न से ValueError। उदाहरण के लिए UnicodeDecodeError

ध्यान दें कि आप जो चाहें जोड़ सकते हैं err। उदाहरण के लिए err.problematic_array=[1,2,3]


संपादित करें: @Ducan टिप्पणी में इंगित करता है कि उपरोक्त अजगर 3 के साथ काम नहीं करता है क्योंकि .messageइसका सदस्य नहीं है ValueError। इसके बजाय आप इसका उपयोग कर सकते हैं (मान्य अजगर 2.6 या बाद में या 3.x):

try:
    try:
      raise ValueError
    except ValueError as err:
       if not err.args: 
           err.args=('',)
       err.args = err.args + ("hello",)
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e.args))

EDIT2:

उद्देश्य क्या है, इसके आधार पर, आप अपने स्वयं के चर नाम के तहत अतिरिक्त जानकारी जोड़ने का विकल्प भी चुन सकते हैं। दोनों python2 और python3 के लिए:

try:
    try:
      raise ValueError
    except ValueError as err:
       err.extra_info = "hello"
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e))
    if 'extra_info' in dir(e):
       print e.extra_info

9
चूंकि आप पायथन 3 शैली अपवाद हैंडलिंग का उपयोग करने के प्रयास में गए हैं और print, आपको संभवतः ध्यान देना चाहिए कि आपका कोड पायथन 3.x में काम नहीं करता है क्योंकि messageअपवादों पर कोई विशेषता नहीं है। err.args = (err.args[0] + " hello",) + err.args[1:]अधिक मज़बूती से काम कर सकते हैं (और फिर संदेश प्राप्त करने के लिए बस एक स्ट्रिंग में परिवर्तित करें)।
डंकन

1
दुर्भाग्य से इस बात की कोई गारंटी नहीं है कि args [0] एक त्रुटि संदेश का प्रतिनिधित्व करने वाला एक स्ट्रिंग प्रकार है - "अपवाद निर्माणकर्ता को दिए गए तर्कों का विवरण। कुछ अंतर्निहित अपवाद (IOError की तरह) एक निश्चित संख्या में तर्क की अपेक्षा करते हैं और एक विशेष अर्थ प्रदान करते हैं। इस टपल के तत्व, जबकि अन्य को आमतौर पर केवल एक एकल स्ट्रिंग के साथ कहा जाता है जो एक त्रुटि संदेश देता है। " तो कोड काम नहीं करेगा arg [0] एक त्रुटि संदेश नहीं है (यह एक इंट हो सकता है, या यह एक फ़ाइल को दर्शाने वाला एक स्ट्रिंग हो सकता है)।
ट्रेंट

1
@ तारा, दिलचस्प। क्या आपके पास उस पर एक संदर्भ है? फिर मैं एक पूरी तरह से नए सदस्य को जोड़ूंगा। या नई और मूल जानकारी को ध्यान में रखते हुए यह सब अपने आप में अलग कर देता है।
जोहान लुंडबर्ग

2
जब args का वास्तविक उदाहरण [0] एक त्रुटि संदेश नहीं है - docs.python.org/2/library/exception.html - "अपवाद EnvironmentError अपवादों के लिए आधार वर्ग जो पायथन सिस्टम के बाहर हो सकता है: IOError, OSError। जब इस प्रकार के अपवादों को 2-ट्यूपल के साथ बनाया जाता है, तो पहला आइटम उदाहरण के इरनो विशेषता (इसे एक त्रुटि संख्या माना जाता है) पर उपलब्ध है, और दूसरा आइटम स्ट्रर विशेषता पर उपलब्ध है (यह आमतौर पर संबद्ध है) त्रुटि संदेश)। टॉगल भी आर्ग्स विशेषता पर उपलब्ध है। "
ट्रेंट

2
मुझे यह बिल्कुल समझ में नहीं आता है। .messageविशेषता स्थापित करने का एकमात्र कारण यह है कि यह विशेषता स्पष्ट रूप से मुद्रित होती है। आप को पकड़ने और मुद्रण के बिना अपवाद को बढ़ाने के लिए कर रहे थे, तो आप हैं नहीं देख .messageविशेषता कुछ भी उपयोगी है।
डैनियलस्कैन

171

यदि आप केवल 3. अजगर का समर्थन करने के लिए पर्याप्त भाग्यशाली हैं, तो यह वास्तव में सुंदरता की बात बन जाता है :)

से बढ़ा

हम ऊपर से उपयोग करके अपवादों की श्रृंखला बना सकते हैं ।

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks') from e

इस स्थिति में, आपका कॉल करने वाला अपवाद उस स्थान की पंक्ति संख्या होगा जहां हम अपना अपवाद बढ़ाते हैं।

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks') from e
Exception: Smelly socks

ध्यान दें कि नीचे के अपवाद में केवल स्टैकट्रेस है जहां से हमने अपना अपवाद उठाया है। आपका कॉलर अभी भी एक्सेस करके मूल अपवाद प्राप्त कर सकता है__cause__ पकड़े गए अपवाद विशेषता ।

with_traceback

या आप with_traceback का उपयोग कर सकते हैं ।

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks').with_traceback(e.__traceback__)

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

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks').with_traceback(e.__traceback__)
  File "test.py", line 2, in <module>
    1 / 0
Exception: Smelly socks

ध्यान दें कि अपवाद में वह रेखा है जहां हमने अमान्य विभाजन के साथ-साथ उस पंक्ति को प्रदर्शित किया है, जहां हम अपवाद को पुन: उत्पन्न करते हैं।


1
क्या अतिरिक्त ट्रेसबैक के बिना किसी अपवाद पर कस्टम संदेश जोड़ना संभव है? उदाहरण के लिए, raise Exception('Smelly socks') from eअपने स्वयं के एक नए ट्रेसबैक को प्रस्तुत करने के बजाय मूल ट्रेसबैक पर एक टिप्पणी के रूप में "स्माइली मोजे" जोड़ने के लिए संशोधित किया जा सकता है।
जोएलोस्टब्लोम

यह व्यवहार आपको जोहान लुंडबर्ग के जवाब से मिलेगा
बेन

3
यह वास्तव में सुंदर है। धन्यवाद।
एलनबेरी

3
एक नया अपवाद या श्रृंखला को फिर से ऊपर उठाना नए संदेशों के साथ अपवादों को उठाना कई मामलों में आवश्यकता से अधिक भ्रम पैदा करता है। खुद के अपवादों को संभालना जटिल है। एक बेहतर रणनीति यह है कि अपने संदेश को मूल अपवाद के तर्क में जोड़ दें, यदि संभव हो तो इरेज़र + = ("संदेश") में संभव हो, और अपवाद संदेश को फिर से बढ़ाएं। ट्रेसबैक आपको उन पंक्ति नंबरों पर नहीं ले जा सकता है जहां अपवाद पकड़ा गया था, लेकिन यह सुनिश्चित करने के लिए अपवाद के लिए आपको ले जाएगा।
उपयोगकर्ता-एस्टेरिक्स

2
आप क्लॉज से कोई भी निर्दिष्ट करके अपवाद श्रृंखला के प्रदर्शन को स्पष्ट रूप से दबा सकते हैं :raise RuntimeError("Something bad happened") from None
pfabri

10
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

प्रिंट:

There is a problem: invalid literal for int() with base 10: 'a'

1
मैं सोच रहा था कि क्या एक पायथन मुहावरे के लिए जो मैं करने की कोशिश कर रहा हूं, एक और उदाहरण बढ़ाने के अलावा ।
किट

@ किट - मैं इसे 'एक अपवाद फिर से जुटाना' कहूंगा
eumiro

1
@eumiro, नहीं, आप एक नया अपवाद बना रहे हैं। मेरा जवाब देखिए। आपके लिंक से: "... लेकिन बिना किसी अभिव्यक्तियों के साथ उठाना पसंद किया जाना चाहिए, यदि मौजूदा दायरे में फिर से उठाया गया अपवाद सबसे हाल ही में सक्रिय अपवाद था।"
जोहान लुंडबर्ग

3
@JohanLundberg - raiseमापदंडों के बिना फिर से बढ़ रहा है। यदि ओपी एक संदेश जोड़ना चाहता है, तो उसे एक नया अपवाद उठाना होगा और मूल अपवाद के संदेश / प्रकार का फिर से उपयोग कर सकता है।
यूमरियो

2
यदि आप एक संदेश जोड़ना चाहते हैं तो आप "ValueError" फेंककर खरोंच से एक नया संदेश नहीं बना सकते। ऐसा करने से, आप अंतर्निहित जानकारी को नष्ट कर देते हैं कि यह किस प्रकार का मूल्य है (C ++ में स्लाइसिंग के समान)। द्वारा फिर से फेंकने ही एक बहस के बिना उठाने के साथ अपवाद, आपको लगता है कि सही विशिष्ट प्रकार (ValueError से प्राप्त) के साथ मूल वस्तु गुजरती हैं।
जोहान लुंडबर्ग

9

ऐसा लगता है कि सभी उत्तर e.args [0] में जानकारी जोड़ रहे हैं, जिससे मौजूदा त्रुटि संदेश बदल जाएगा। क्या इसके स्थान पर आर्गन्स टपल का विस्तार करना नकारात्मक है? मुझे लगता है कि संभव उल्टा है, आप उन मामलों के लिए मूल त्रुटि संदेश को अकेले छोड़ सकते हैं जहां स्ट्रिंग की आवश्यकता होती है; और अगर आप अपने कस्टम त्रुटि हैंडलिंग कई संदेश या त्रुटि कोड का उत्पादन किया है, जहां ट्रेसबैक प्रोग्रामेटिकली पार्स (जैसे सिस्टम निगरानी उपकरण के माध्यम से)।

## Approach #1, if the exception may not be derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args = (e.args if e.args else tuple()) + ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

या

## Approach #2, if the exception is always derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args += ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

आप इस दृष्टिकोण के लिए एक नकारात्मक पहलू देख सकते हैं?


मेरे पुराने उत्तर में परिवर्तन नहीं होता है। [0]
जोहान लुंडबर्ग

4

यह कोड टेम्प्लेट आपको एक कस्टम संदेश के साथ एक अपवाद बढ़ाने की अनुमति देता है।

try:
     raise ValueError
except ValueError as err:
    raise type(err)("my message")

3
यह स्टैक ट्रेस को संरक्षित नहीं करता है।
प्रातः

प्रश्नकर्ता यह निर्दिष्ट नहीं करता है कि स्टैक ट्रेस संरक्षित किया जाए।
shrewmouse

4

या तो अपने त्रुटि संदेश का उपयोग करके नए अपवाद को बढ़ाएं

raise Exception('your error message')

या

raise ValueError('your error message')

उस स्थान के भीतर जहां आप इसे उठाना चाहते हैं या 'से' का उपयोग करके वर्तमान अपवाद में त्रुटि संदेश संलग्न (प्रतिस्थापित) करते हैं (केवल पायथन 3.x):

except ValueError as e:
  raise ValueError('your message') from e

Thanx, @gberger, 'e' दृष्टिकोण से वास्तव में अजगर द्वारा समर्थित नहीं है 2.x
एलेक्सी एंटोनेंको

3

यह वह फ़ंक्शन है जिसका उपयोग मैं मूल ट्रेसबैक को संरक्षित करते हुए पायथन 2.7 और 3.x में अपवाद संदेश को संशोधित करने के लिए करता हूं। इसकी जरूरत हैsix

def reraise_modify(caught_exc, append_msg, prepend=False):
    """Append message to exception while preserving attributes.

    Preserves exception class, and exception traceback.

    Note:
        This function needs to be called inside an except because
        `sys.exc_info()` requires the exception context.

    Args:
        caught_exc(Exception): The caught exception object
        append_msg(str): The message to append to the caught exception
        prepend(bool): If True prepend the message to args instead of appending

    Returns:
        None

    Side Effects:
        Re-raises the exception with the preserved data / trace but
        modified message
    """
    ExceptClass = type(caught_exc)
    # Keep old traceback
    traceback = sys.exc_info()[2]
    if not caught_exc.args:
        # If no args, create our own tuple
        arg_list = [append_msg]
    else:
        # Take the last arg
        # If it is a string
        # append your message.
        # Otherwise append it to the
        # arg list(Not as pretty)
        arg_list = list(caught_exc.args[:-1])
        last_arg = caught_exc.args[-1]
        if isinstance(last_arg, str):
            if prepend:
                arg_list.append(append_msg + last_arg)
            else:
                arg_list.append(last_arg + append_msg)
        else:
            arg_list += [last_arg, append_msg]
    caught_exc.args = tuple(arg_list)
    six.reraise(ExceptClass,
                caught_exc,
                traceback)


2

वर्तमान उत्तर मेरे लिए अच्छा काम नहीं करता था, यदि अपवाद को फिर से नहीं पकड़ा जाता है तो संलग्न संदेश नहीं दिखाया जाता है।

लेकिन नीचे की तरह करना दोनों ही ट्रेस रखता है और अपडाउन किए गए मैसेज को दिखाता है फिर चाहे अपवाद फिर से पकड़ा जाए या नहीं।

try:
  raise ValueError("Original message")
except ValueError as err:
  t, v, tb = sys.exc_info()
  raise t, ValueError(err.message + " Appended Info"), tb

(मैंने पायथन 2.7 का उपयोग किया है, इसे पायथन 3 में आज़माया नहीं है)


1

उपरोक्त समाधानों में से कोई भी ऐसा नहीं था जो मैं चाहता था, जो कि त्रुटि संदेश के पहले भाग में कुछ जानकारी जोड़ना था, यानी मैं चाहता था कि मेरे उपयोगकर्ता पहले मेरा कस्टम संदेश देखें।

यह मेरे लिए काम किया:

exception_raised = False
try:
    do_something_that_might_raise_an_exception()
except ValueError as e:
    message = str(e)
    exception_raised = True

if exception_raised:
    message_to_prepend = "Custom text"
    raise ValueError(message_to_prepend + message)

0

यह केवल पायथन 3 के साथ काम करता है । आप अपवाद के मूल तर्कों को संशोधित कर सकते हैं और अपने तर्क जोड़ सकते हैं।

एक अपवाद याद रखता है कि यह जिस args के साथ बनाया गया था। मुझे लगता है कि यह इतना है कि आप अपवाद को संशोधित कर सकते हैं।

फ़ंक्शन में reraiseहम किसी भी नए तर्कों के साथ अपवाद के मूल तर्क को प्रस्तुत करते हैं जो हम चाहते हैं (जैसे संदेश)। अंत में हम ट्रेस-बैक इतिहास को संरक्षित करते हुए अपवाद को फिर से बढ़ाते हैं।

def reraise(e, *args):
  '''re-raise an exception with extra arguments
  :param e: The exception to reraise
  :param args: Extra args to add to the exception
  '''

  # e.args is a tuple of arguments that the exception with instantiated with.
  #
  e.args = args + e.args

  # Recreate the expection and preserve the traceback info so thta we can see 
  # where this exception originated.
  #
  raise e.with_traceback(e.__traceback__)   


def bad():
  raise ValueError('bad')

def very():
  try:
    bad()
  except Exception as e:
    reraise(e, 'very')

def very_very():
  try:
    very()
  except Exception as e:
    reraise(e, 'very')

very_very()

उत्पादन

Traceback (most recent call last):
  File "main.py", line 35, in <module>
    very_very()
  File "main.py", line 30, in very_very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 28, in very_very
    very()
  File "main.py", line 24, in very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 22, in very
    bad()
  File "main.py", line 18, in bad
    raise ValueError('bad')
ValueError: ('very', 'very', 'bad')

-3

यदि आप त्रुटि प्रकार को कस्टम करना चाहते हैं, तो एक साधारण चीज जो आप कर सकते हैं वह है ValueError के आधार पर त्रुटि वर्ग को परिभाषित करना।


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