अजगर: मुझे कैसे पता चलेगा कि किस प्रकार का अपवाद हुआ?


230

मेरे पास एक कार्यक्रम है जिसे मुख्य कार्यक्रम द्वारा बुलाया गया है:

try:
    someFunction()
except:
    print "exception happened!"

लेकिन फ़ंक्शन के निष्पादन के बीच में यह अपवाद को जन्म देता है, इसलिए यह exceptभाग को कूदता है ।

मैं यह कैसे देख सकता हूं someFunction()कि इसमें जो अपवाद हुआ, उसका कारण क्या है?


9
कभी भी कभी नंगे except:(बिना नंगे raise) का उपयोग करें , शायद एक बार कार्यक्रम के अलावा, और अधिमानतः तब नहीं।
माइक ग्राहम

यदि आप कई exceptप्रकारों का उपयोग करते हैं, तो आपको अपवाद प्रकार की जांच करने की आवश्यकता नहीं होगी, जो कि आमतौर पर एक विशिष्ट अपवाद प्रकार के अनुसार कार्य करने के लिए किया जाता है।
रिक पोगी

3
यदि आप अपवाद के प्रकार के बारे में परवाह करते हैं, तो यह इसलिए है क्योंकि आपने पहले ही विचार कर लिया है कि तार्किक रूप से किस प्रकार के अपवाद हो सकते हैं।
कार्ल केनचेल

3
इनसाइड exceptब्लॉक इन sys.exc_info()फंक्शन के माध्यम से अपवाद उपलब्ध है - यह फ़ंक्शन तीन मानों का एक टपल देता है जो उस अपवाद के बारे में जानकारी देता है जो वर्तमान में नियंत्रित किया जा रहा है।
पायोत्र डोब्रोगोस्ट

जवाबों:


384

अन्य जवाब सभी को इंगित करते हैं कि आपको सामान्य अपवादों को नहीं पकड़ना चाहिए, लेकिन कोई भी आपको यह नहीं बताना चाहता है कि क्यों, यह समझना आवश्यक है कि आप "नियम" को कब तोड़ सकते हैं। यहाँ एक स्पष्टीकरण है। असल में, यह इतना है कि आप छिपाएँ नहीं:

तो जब तक आप उन चीजों में से कोई भी करने के लिए ध्यान रखते हैं, तो सामान्य अपवाद को पकड़ना ठीक है। उदाहरण के लिए, आप उपयोगकर्ता को किसी अन्य तरीके से अपवाद के बारे में जानकारी प्रदान कर सकते हैं, जैसे:

  • GUI में संवाद के रूप में अपवाद प्रस्तुत करें
  • एक श्रमिक थ्रेड या प्रक्रिया को नियंत्रित करने वाले थ्रेड या प्रक्रिया से स्थानांतरण को एक मल्टीथ्रेडिंग या मल्टीप्रोसेसिंग अनुप्रयोग में स्थानांतरित करें

तो जेनेरिक अपवाद को कैसे पकड़ा जाए? इसके कई तरीके हैं। यदि आप केवल अपवाद ऑब्जेक्ट चाहते हैं, तो इसे इस तरह से करें:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

सुनिश्चित करें किmessage उपयोगकर्ता को हार्ड-टू-मिस तरीके से ध्यान में लाया जाए! जैसा कि ऊपर दिखाया गया है, इसे प्रिंट करना काफी नहीं हो सकता है अगर संदेश बहुत सारे अन्य संदेशों में दफन है। उपयोगकर्ताओं का ध्यान आकर्षित करने में असफल होना सभी अपवादों को निगलने के लिए कठिन है, और अगर इस पृष्ठ पर उत्तरों को पढ़ने के बाद आपको एक छाप छोड़नी चाहिए, तो यह एक अच्छी बात नहीं है । एक raiseबयान के साथ अपवाद ब्लॉक को समाप्त करने से समस्या को पारदर्शी तरीके से रोककर समस्या को हल किया जाएगा जो पकड़ा गया था।

except:बिना किसी तर्क के उपरोक्त और उपयोग के बीच का अंतर दो गुना है:

  • एक नंगे except:आपको निरीक्षण करने के लिए अपवाद वस्तु नहीं देता है
  • अपवाद SystemExit, KeyboardInterruptऔर GeneratorExitउपरोक्त कोड द्वारा नहीं पकड़े गए, जो आम तौर पर आप चाहते हैं। अपवाद पदानुक्रम देखें ।

यदि आप भी वही स्टैकट्रेस चाहते हैं जो आपको मिलती है यदि आप अपवाद नहीं पकड़ते हैं, तो आप इस तरह प्राप्त कर सकते हैं (अभी भी अपवाद को छोड़कर):

import traceback
print traceback.format_exc()

यदि आप loggingमॉड्यूल का उपयोग करते हैं , तो आप लॉग को अपवाद (संदेश के साथ) इस तरह से प्रिंट कर सकते हैं:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

यदि आप गहरी खुदाई करना चाहते हैं और स्टैक की जांच करना चाहते हैं, तो चर आदि देखें, अपवाद ब्लॉक के अंदर मॉड्यूल के post_mortemफ़ंक्शन का उपयोग करें pdb:

import pdb
pdb.post_mortem()

जब मैं नीचे शिकार कर रहा हूं तो मुझे यह अंतिम विधि अमूल्य लगी।


1
ट्रेसबैक.प्रिंट_एक्ससी () आपके अधिक जटिल "" के समान काम करेगा। "
गुरगह

1
@ गुरुजी हां, लेकिन मुझे नहीं पता कि वह इसे प्रिंट करना चाहते हैं या इसे किसी फाइल में सेव करना चाहते हैं या लॉग इन करना चाहते हैं या इसके साथ कुछ और करना चाहते हैं।
लॉरिट्ज़ वी। थुलो

मैं निराश नहीं था, लेकिन मैं कहूंगा कि क्योंकि आपको शुरुआत में यह कहते हुए बहुत बड़ी चर्बी लगानी चाहिए थी कि आपको इसमें से किसी की आवश्यकता नहीं होनी चाहिए, लेकिन यहाँ यह कैसे किया जा सकता है । और शायद इसलिए कि आप सामान्य अपवाद को पकड़ने का सुझाव देते हैं।
रिक पोगी

10
@ रिक मुझे लगता है कि आपको इस सब की बहुत आवश्यकता हो सकती है । उदाहरण के लिए, यदि आपका GUI और बैकएंड के साथ कोई प्रोग्राम है, और आप अपने प्रोग्राम को स्टैक ट्रेस के साथ छोड़ने के बजाय GUI संदेशों के रूप में बैकएंड से सभी अपवाद प्रस्तुत करना चाहते हैं। ऐसे मामले में, आपको जेनेरिक अपवाद को पकड़ना चाहिए , संवाद के लिए एक ट्रेसबैक टेक्स्ट बनाएं, अपवाद भी लॉग इन करें, और यदि डिबग मोड में है, तो पोस्टमार्टम दर्ज करें।
लॉरिट्ज वी। थुलोव

18
@ रीकपोगी: भोली सोच। जब आपको किसी और के कोड से अपवादों को पकड़ने की आवश्यकता होती है, तो कई उचित परिस्थितियां होती हैं और आपको यह नहीं पता होता है कि क्या अपवाद उठाए जाएंगे।
stackoverflowuser2010

63

उस वर्ग का नाम प्राप्त करें जो अपवाद वस्तु है:

e.__class__.__name__

और print_exc () फ़ंक्शन का उपयोग करके स्टैक ट्रेस भी प्रिंट होगा जो किसी भी त्रुटि संदेश के लिए आवश्यक जानकारी है।

ऐशे ही:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception, e:
    print 'type is:', e.__class__.__name__
    print_exc()
    # print "exception happened!"

आपको इस तरह आउटपुट मिलेगा:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

और प्रिंट और विश्लेषण के बाद, कोड अपवाद को संभालने और बस निष्पादित करने का निर्णय नहीं ले सकता है raise:

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"

आउटपुट:

special case of CustomException not interfering

और दुभाषिया प्रिंट अपवाद:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

raiseमूल अपवाद के बाद कॉल स्टैक को और अधिक प्रचारित करना जारी है। ( संभावित नुकसान से सावधान ) यदि आप नया अपवाद उठाते हैं तो यह नए (छोटे) स्टैक ट्रेस की देखभाल करता है।

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        #raise CustomException(e.message)
        raise e
    print "handling exception"

आउटपुट:

special case of CustomException not interfering
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

ध्यान दें कि ट्रेसबैक में calculate()फ़ंक्शन को लाइन से शामिल नहीं 9किया गया है जो मूल अपवाद का मूल है e


आप एक स्ट्रिंग के रूप ट्रैस बैक संग्रहीत करना चाहते हैं, तो आप उपयोग कर सकते हैं traceback.format_exc()और साथ ही
Stevoisiak

1
e.__class__.__name__क्या यह वैसा ही है type(e).__name__, जैसा कि ऊपर दिए गए जवाब से पता चलता है?
information_interchange

1
@information_interchange हाँ। प्रश्न और स्वीकृत उत्तर सामग्री समय के साथ पूरी तरह से बदल गई। यह शर्म की बात है अन्य प्रतिभागियों को एसओ मशीनरी द्वारा सूचित नहीं किया जाता है :(
एलेक्स

14

आपको आमतौर पर सभी संभावित अपवादों को नहीं पकड़ना चाहिए try: ... exceptक्योंकि यह अत्यधिक व्यापक है। बस उन्हीं को पकड़ें जो किसी भी कारण से होने की उम्मीद है। यदि आपको वास्तव में उदाहरण के लिए, यदि आप डिबगिंग करते समय किसी समस्या के बारे में अधिक जानकारी प्राप्त करना चाहते हैं, तो आपको करना चाहिए

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.

17
यहाँ "कभी नहीं" शब्द का प्रयोग कभी गलत नहीं हुआ। मैं try: ... except Exception:बहुत सी चीजों का उपयोग करता हूं , उदाहरण के लिए नेटवर्क पर निर्भर पुस्तकालयों का उपयोग, या एक डेटा मालिश जो अजीब सामान उसे भेजा जा सकता है। स्वाभाविक रूप से मेरे पास उचित लॉगिंग भी है। यह इनपुट डेटा में एक गलती के मामले में प्रोग्राम को जारी रखने की अनुमति देने के लिए महत्वपूर्ण है।
थनी जूल 3'13

3
कभी उन सभी अपवादों को पकड़ने की कोशिश की जो ईमेल का उपयोग करते समय उठाए जा सकते हैं smtplib?
लिनसग

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

1
सभी अपवादों को पकड़ना पूरी तरह से उचित है। यदि आप किसी तीसरे पक्ष के पुस्तकालय को बुला रहे हैं, तो आप यह नहीं जान सकते हैं कि उस पुस्तकालय में क्या अपवाद उठाए जाएंगे। ऐसे मामले में, एकमात्र अपवाद सभी अपवादों को पकड़ना है, उदाहरण के लिए उन्हें एक फ़ाइल में लॉग इन करना।
stackoverflowuser2010

ठीक है तुम ठीक कह रहे हो, मैं अपना उत्तर स्पष्ट कर दूंगा कि सभी को पकड़ने के लिए वैध उपयोग के मामले हैं।
hochl

10

जब तक somefunctionएक बहुत बुरा कोडित विरासत समारोह नहीं होता है, तो आपको उस चीज़ की आवश्यकता नहीं होनी चाहिए जो आप पूछ रहे हैं।

exceptअलग-अलग तरीकों से अलग-अलग अपवादों को संभालने के लिए कई खंडों का उपयोग करें :

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else

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


8
यदि आप किसी तृतीय-पक्ष लाइब्रेरी का उपयोग कर रहे हैं, तो आप यह नहीं जान सकते हैं कि इसके अंदर क्या अपवाद उठाए जाएंगे। आप संभवतः उन सभी को व्यक्तिगत रूप से कैसे पकड़ सकते हैं?
stackoverflowuser2010

8

अधिकांश उत्तर except (…) as (…):वाक्य-विन्यास की ओर इशारा करते हैं (ठीक है इसलिए) लेकिन उसी समय कोई भी कमरे में एक हाथी के बारे में बात नहीं करना चाहता है, जहां हाथी sys.exc_info()कार्य करता है। Sys मॉड्यूल के दस्तावेज से (जोर मेरा):

यह फ़ंक्शन तीन मानों का एक टपल देता है जो उस अपवाद के बारे में जानकारी देता है जो वर्तमान में नियंत्रित किया जा रहा है।
(…)
यदि स्टैक पर कहीं भी कोई अपवाद नहीं संभाला जा रहा है, तो एक टपल जिसमें तीन कोई नहीं है मान लौटाया गया है। अन्यथा, लौटाए गए मान हैं (प्रकार, मान, ट्रेसबैक)। उनका अर्थ है: प्रकार को अपवादित किए जाने का प्रकार मिलता है (बेसएक्ससेप्शन का एक उपवर्ग); मान अपवाद अपवाद (अपवाद प्रकार का एक उदाहरण) प्राप्त करता है; ट्रेसबैक को एक ट्रेसबैक ऑब्जेक्ट (संदर्भ मैनुअल देखें) मिलता है जो कॉल स्टैक को उस बिंदु पर एन्क्रिप्ट करता है जहां मूल रूप से अपवाद हुआ था।

मुझे लगता है कि मुझे sys.exc_info()मूल प्रश्न का सबसे सीधा जवाब माना जा सकता है कि मुझे कैसे पता चलेगा कि किस प्रकार का अपवाद हुआ?


1
यह मेरे लिए सही उत्तर है क्योंकि यह इस समस्या को हल करता है कि अपवाद क्या हो रहा है इसलिए मुझे नंगे के बजाय क्या रखना चाहिए except। बस पूर्णता के लिए, exctype, value = sys.exc_info()[:2]आपको अपवाद प्रकार बताएगा जो तब उपयोग किया जा सकता है except
ओन्ड्रेज बर्कर्ट

5

कोशिश: कुछ अपवाद () अपवाद को छोड़कर, exc:

#this is how you get the type
excType = exc.__class__.__name__

#here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)

#It's easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))

-1 का उपयोग करते हुए exc.__class__.__name__पहले से ही एलेक्स के जवाब में सुझाव दिया गया था - stackoverflow.com/a/9824060/95735
पायोटर डोब्रोगोस्ट

3

डिबगिंग के लिए ये उत्तर ठीक हैं, लेकिन क्रमिक रूप से अपवाद का isinstance(e, SomeException)परीक्षण करने के लिए, यह आसान हो सकता है, क्योंकि यह उप-वर्ग के लिए SomeExceptionभी परीक्षण करता है, इसलिए आप कार्यक्षमता बना सकते हैं जो अपवादों के पदानुक्रम पर लागू होती है।


1

यहां बताया गया है कि मैं अपने अपवादों को कैसे संभाल रहा हूं। यह विचार करना आसान है कि समस्या को हल करने का प्रयास करें, और बाद में यदि संभव हो तो अधिक वांछनीय समाधान जोड़ें। उस कोड में समस्या को हल न करें जो अपवाद उत्पन्न करता है, या वह कोड मूल एल्गोरिथ्म का ट्रैक खो देता है, जिसे-टू-पॉइंट लिखा जाना चाहिए। हालाँकि, समस्या को हल करने के लिए कौन से डेटा की आवश्यकता है, और केवल एक लैम्ब्डा वापस करें यदि आप उस कोड के बाहर की समस्या को हल नहीं कर सकते जो इसे उत्पन्न करता है।

path = 'app.p'

def load():
    if os.path.exists(path):
        try:
            with open(path, 'rb') as file:
                data = file.read()
                inst = pickle.load(data)
        except Exception as e:
            inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
    else:
        inst = App()
    inst.loadWidgets()

# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
    class_name = e.__class__.__name__
    print(class_name + ': ' + str(e))
    print('\t during: ' + during)
    return easy

अभी के लिए, चूंकि मैं अपने ऐप के उद्देश्य के लिए महत्वपूर्ण रूप से सोचना नहीं चाहता, इसलिए मैंने कोई जटिल समाधान नहीं जोड़ा है। लेकिन भविष्य में, जब मैं संभावित समाधानों के बारे में अधिक जानता हूं (चूंकि एप्लिकेशन को अधिक डिज़ाइन किया गया है), तो मैं अनुक्रमित समाधानों के शब्दकोश में जोड़ सकता हूंduring

दिखाए गए उदाहरण में, एक समाधान कहीं और स्टोर किए गए ऐप डेटा को देखने के लिए हो सकता है, अगर 'app.p' फ़ाइल गलती से हटा दी गई हो।

अभी के लिए, चूंकि अपवाद हैंडलर लिखना एक स्मार्ट विचार नहीं है (हम अभी तक इसे हल करने के सर्वोत्तम तरीकों को नहीं जानते हैं, क्योंकि ऐप डिज़ाइन विकसित हो जाएगा), हम बस आसान फिक्स लौटाते हैं जो हम चल रहे हैं जैसे कार्य करना है पहली बार के लिए एप्लिकेशन (इस मामले में)।


0

लॉरिट्स के उत्तर में जोड़ने के लिए, मैंने अपवाद से निपटने के लिए एक डेकोरेटर / रैपर बनाया और रैपर लॉग जो अपवाद का प्रकार था।

class general_function_handler(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kwargs):
        try:
            retval = self.func(*args, **kwargs)
        except Exception, e :
            logging.warning('Exception in %s' % self.func)
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(e).__name__, e.args)
            logging.exception(message)
            sys.exit(1) # exit on all exceptions for now
        return retval

इसे डेकोरेटर के साथ क्लास मेथड या स्टैंडअलोन फंक्शन पर बुलाया जा सकता है:

@general_function_handler

मेरे ब्लॉग को पूर्ण उदाहरण के लिए देखें: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/


0

आप लॉरिट्ज की सिफारिश के साथ शुरू कर सकते हैं:

except Exception as ex:

और फिर बस print exइतना पसंद करने के लिए:

try:
    #your try code here
except Exception as ex:
    print ex

क्या आप थोड़ा विस्तृत कर सकते हैं ताकि आपका उत्तर अकेला खड़ा हो?
जीएचसी

1
सुनिश्चित करें: आप इस तरह से पकड़े गए अपवाद को प्रिंट कर सकते हैं: प्रयास करें: #your कोड को अपवाद के रूप में अपवाद के रूप में यहां देखें: प्रिंट पूर्व अब त्रुटि मुद्रित की जाएगी
Gura


-2

आपका प्रश्न यह है: "मैं कैसे देख सकता हूँ कि क्या हुआ है कुछ फंक्शन () में जो अपवाद हुआ है?"

यह मुझे लगता है कि आप उत्पादन कोड में अप्रत्याशित अपवादों को संभालने के बारे में नहीं पूछ रहे हैं (जैसा कि कई जवाब माना जाता है), लेकिन यह कैसे पता लगाएं कि विकास के दौरान एक विशेष अपवाद का कारण क्या है।

सबसे आसान तरीका एक डिबगर का उपयोग करना है जो रोक सकता है जहां अनियोजित अपवाद होता है, अधिमानतः बाहर निकलना नहीं, ताकि आप चर का निरीक्षण कर सकें। उदाहरण के लिए, ग्रहण खुला स्रोत IDE में PyDev ऐसा कर सकता है। सक्षम करने के लिए, ग्रहण में, डीबग परिप्रेक्ष्य खोलें, मेनू Manage Python Exception Breakpointsमें चयन करें Run, और जांचें Suspend on uncaught exceptions


-4

केवल अपवाद को पकड़ने से बचना और ट्रेसबैक कि पायथन प्रिंट आपको बताएगा कि क्या अपवाद हुआ।

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