एक अपवाद ऑब्जेक्ट से ट्रेसबैक जानकारी निकालें


111

अपवाद वस्तु (अज्ञात मूल के) को देखते हुए इसके ट्रेसबैक प्राप्त करने का कोई तरीका है? मेरे पास इस तरह का कोड है:

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

एक बार मेरे पास अपवाद वस्तु से ट्रेसबैक कैसे निकाला जा सकता है?

जवाबों:


92

इस प्रश्न का उत्तर आपके द्वारा उपयोग किए जा रहे पायथन के संस्करण पर निर्भर करता है।

पायथन 3 में

यह सरल है: अपवाद एक __traceback__विशेषता से सुसज्जित हैं जिसमें ट्रेसबैक शामिल है। यह विशेषता भी लेखन योग्य है, और with_tracebackअपवादों की विधि का उपयोग करके आसानी से सेट किया जा सकता है:

raise Exception("foo occurred").with_traceback(tracebackobj)

इन सुविधाओं को न्यूनतम raiseप्रलेखन के भाग के रूप में वर्णित किया गया है ।

उत्तर के इस भाग का सारा श्रेय वैक्टर को जाना चाहिए, जिसने पहली बार यह जानकारी पोस्ट की थी । मैं इसे यहां केवल इसलिए शामिल कर रहा हूं क्योंकि यह उत्तर सबसे ऊपर है, और पायथन 3 अधिक आम है।

अजगर 2 में

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

इसे हल करने का अच्छा तरीका यह होगा कि क्लॉज को छोड़ने के बाद सर्जिकल तोड़ दिया जाएexcept , जो कि पायथन 3 करता है। पायथन 2 समाधान बहुत बदसूरत है: आपको एक तदर्थ फ़ंक्शन प्रदान किया जाता है sys.exc_info(), जो केवल except क्लॉज़ के अंदर काम करता है । यह अपवाद, अपवाद प्रकार, और जो कुछ भी अपवाद वर्तमान में संभाला जा रहा है, उसके लिए ट्रेसबैक युक्त टपल लौटाता है।

इसलिए यदि आप exceptक्लॉज के अंदर हैं , तो आप मॉड्यूल sys.exc_info()के साथ-साथ tracebackविभिन्न उपयोगी चीजें करने के लिए आउटपुट का उपयोग कर सकते हैं:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

लेकिन जैसा कि आपका संपादन इंगित करता है, आप ट्रेसबैक प्राप्त करने की कोशिश कर रहे हैं जो कि आपके अपवाद को नियंत्रित न करने पर मुद्रित किया गया होता , क्योंकि यह पहले ही संभाला जा चुका है । यह बहुत कठिन सवाल है। दुर्भाग्य से, कोई अपवाद नहीं होने पर sys.exc_infoरिटर्न (None, None, None)। अन्य संबंधित sysविशेषताएँ भी मदद नहीं करती हैं। sys.exc_tracebackकोई अपवाद नहीं होने पर पदावनत और अपरिभाषित है; sys.last_tracebackसही लगता है, लेकिन यह केवल इंटरेक्टिव सत्रों के दौरान परिभाषित किया गया प्रतीत होता है।

यदि आप यह नियंत्रित कर सकते हैं कि अपवाद कैसे उठाया जाता है, तो आप कुछ जानकारी संग्रहीत करने के लिए उपयोग करने में सक्षम हो सकते हैं inspectऔर एक कस्टम अपवाद हो सकता है । लेकिन मुझे पूरी तरह से यकीन नहीं है कि यह कैसे काम करेगा।

सच्चाई बताने के लिए, एक अपवाद को पकड़ना और वापस करना एक असामान्य बात है। यह एक संकेत हो सकता है कि आपको वैसे भी रिफ्लेक्टर करने की आवश्यकता है।


मैं इस बात से सहमत हूं कि अपवादों को वापस करना किसी भी तरह से अपरंपरागत है, लेकिन इसके पीछे कुछ औचित्य के लिए मेरा अन्य प्रश्न देखें ।
जॉर्ज

@ thg435, ठीक है, यह तब और अधिक समझ में आ रहा है। कॉलबैक दृष्टिकोणsys.exc_info के साथ संयोजन में मेरे उपरोक्त समाधान पर विचार करें जो मैं आपके अन्य प्रश्न पर सुझाव देता हूं।
प्रेषित जूल

ट्रेसबैक ऑब्जेक्ट्स पर अधिक जानकारी (बहुत कम): docs.python.org/3/library/types.html#types.TracebackType docs.python.org/3/reference/datamodel.htmlttback-objects
0xfede7c8

69

चूंकि पायथन 3.0 [PEP 3109] में निर्मित वर्ग Exceptionमें एक __traceback__विशेषता होती है जिसमें एक traceback object(अजगर 3.2.3 के साथ) होता है:

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

समस्या यह है कि थोड़ी देर के लिए Googling__traceback__ के बाद मुझे केवल कुछ लेख मिले लेकिन उनमें से कोई भी वर्णन नहीं करता है कि आपको (या नहीं) का उपयोग करना चाहिए या नहीं __traceback__

हालाँकि, पायथन 3 प्रलेखन के लिएraise कहता है कि:

एक ट्रेसबैक ऑब्जेक्ट आम तौर पर स्वचालित रूप से बनाया जाता है जब एक अपवाद उठाया जाता है और इसे __traceback__विशेषता के रूप में संलग्न किया जाता है , जो कि लेखन योग्य है।

इसलिए मुझे लगता है कि इसका उपयोग किया जाना है।


4
हाँ, इसका उपयोग किया जाना है। से नया क्या है में अजगर 3.0 "पीईपी 3134-: अपवाद अब के रूप में उनके ट्रैस बैक की दुकान वस्तुओं ट्रैस बैक विशेषता यह साधन एक अपवाद वस्तु अब एक अपवाद से संबंधित सभी जानकारी है, जो है, और वहाँ कम कारणों sys.exc_info उपयोग करने के लिए कर रहे हैं () (। हालांकि बाद को हटाया नहीं गया है)। "
मैकीज स्ज़पाकोस्की

मुझे वास्तव में समझ नहीं आ रहा है कि यह उत्तर इतना झिझकने वाला और समान क्यों है। यह एक प्रॉपर्टी है; यह "उपयोग करने के लिए अभिप्रेत" क्यों नहीं होगा?
मार्क अमेरी

2
@MarkAmery संभवतः __नाम में इंगित करता है कि यह एक कार्यान्वयन विवरण है, सार्वजनिक संपत्ति नहीं है?
बेसिक

4
@ बासिक ऐसा नहीं है जो यहाँ इंगित करता है। पाइथन में पारंपरिक रूप __fooसे एक निजी पद्धति है लेकिन __foo__(अंडरस्कोरिंग के साथ भी) एक "जादू" विधि है (और निजी नहीं)।
मार्क अमेरी

1
FYI करें, यह __traceback__विशेषता 100% सुरक्षित है जो आपको पसंद है, जिसका कोई GC प्रभाव नहीं है। यह कहना मुश्किल है कि प्रलेखन से, लेकिन ecatmur को मुश्किल साक्ष्य मिले ।
15

38

पायथन 3 में एक अपवाद ऑब्जेक्ट से स्ट्रिंग के रूप में ट्रेसबैक पाने का एक तरीका:

import traceback

# `e` is an exception object that you get from somewhere
traceback_str = ''.join(traceback.format_tb(e.__traceback__))

traceback.format_tb(...)तार की सूची देता है। ''.join(...)उनका साथ देता है। अधिक संदर्भ के लिए, कृपया देखें: https://docs.python.org/3/library/traceback.html#traceback.format_tb


21

एक तरफ के रूप में, यदि आप वास्तव में पूर्ण ट्रेसबैक प्राप्त करना चाहते हैं, जैसा कि आप इसे अपने टर्मिनल पर मुद्रित करना चाहते हैं, तो आप यह चाहते हैं:

>>> try:
...     print(1/0)
... except Exception as e:
...     exc = e
...
>>> exc
ZeroDivisionError('division by zero')
>>> tb_str = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__)
>>> tb_str
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: division by zero\n']
>>> print("".join(tb_str))
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

यदि आप format_tbउपर्युक्त उत्तरों के अनुसार उपयोग करते हैं, तो आपको कम जानकारी मिलेगी:

>>> tb_str = "".join(traceback.format_tb(exc.__traceback__))
>>> print("".join(tb_str))
  File "<stdin>", line 2, in <module>

4
आखिरकार! यह शीर्ष उत्तर होना चाहिए। धन्यवाद, डैनियल!
दानी

3
आर्ग, मैंने पिछले 20 मिनट बिताए थे, यह पता लगाने से पहले मैंने यह पता लगाया कि :-) etype=type(exc)अब btw को छोड़ा जा सकता है: "संस्करण 3.5 में बदला: एटाइप तर्क को अनदेखा किया गया है और मूल्य के प्रकार से अनुमान लगाया गया है।" docs.python.org/3.7/library/… पायथन 3.7.3 में परीक्षण किया गया।
सिरो सेंटिल्ली 郝海东 冠状 iro 事件 法轮功 19

8

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

केवल एक चीज के बारे में मैं सोच सकता हूं कि आपके लिए ग्लोबल्स को बंद करना होगा stuffताकि जब यह लगे कि यह पकड़ रहा है तो Exceptionयह वास्तव में एक विशेष प्रकार को पकड़ रहा है और अपवाद आपको कॉलर के रूप में प्रचारित करता है:

module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
    stuff()
except Exception:
    import sys
    print sys.exc_info()

7
ये गलत है। पायथन 3 अपवाद के रूप में ट्रेसबैक ऑब्जेक्ट डालता है e.__traceback__
ग्लेन मेनार्ड

6
@GlennMaynard Python 3 exceptब्लॉक से बाहर निकलने पर अपवाद लक्ष्य को हटाकर, पीईआर 3110 के अनुसार समस्या का समाधान करता है ।
परमानंद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.