Ketika saya menangkap pengecualian, bagaimana cara saya mendapatkan jenis, file, dan nomor baris?

251

Menangkap pengecualian yang akan dicetak seperti ini:

Traceback (most recent call last):
  File "c:/tmp.py", line 1, in <module>
    4 / 0
ZeroDivisionError: integer division or modulo by zero

Saya ingin memformatnya menjadi:

ZeroDivisonError, tmp.py, 1
Claudiu
sumber
5
Gunakan modul traceback bawaan .
Ned Deily
Mungkin juga bermanfaat untuk mencetak baris kode, di mana pengecualian terjadi: lihat stackoverflow.com/questions/14519177/…
Apogentus

Jawaban:

380
import sys, os

try:
    raise NotImplementedError("No error")
except Exception as e:
    exc_type, exc_obj, exc_tb = sys.exc_info()
    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
    print(exc_type, fname, exc_tb.tb_lineno)
Semut Aasma
sumber
51
Anda harus berhati-hati tentang membongkar sys.exc_info () ke dalam variabel lokal, karena jika Anda mendapatkan pengecualian di handler kecuali, vars lokal bisa disimpan dalam referensi melingkar dan tidak GC. Praktik terbaik adalah selalu menggunakan irisan dari sys.exc_info () sebagai gantinya. Atau gunakan modul lain seperti traceback, seperti yang disarankan poster lainnya.
Daniel Pryden
1
Apakah tb hanya exc_tb? dan os.path.split (blabla) [1] adalah os.path.basename (balbal)
sunqiang
4
@ Basj: Dengan sys.exc_info () [0] .__ name__ Anda mendapatkan nama sederhana dari tipe tersebut.
Johannes Overmann
5
@DanielPryden Python docs juga menggunakan metode unpacking yang sama docs.python.org/2/library/traceback.html#traceback-examples
pengguna
3
@RobM: Ya, aman-utas. sys.exc_info()diperkenalkan untuk menangani masalah keamanan benang di API sebelumnya. Keluarannya khusus untuk utas saat ini dan bingkai tumpukan saat ini.
user2357112 mendukung Monica
125

Bentuk paling sederhana yang bekerja untuk saya.

import traceback

try:
    print(4/0)
except ZeroDivisionError:
    print(traceback.format_exc())

Keluaran

Traceback (most recent call last):
  File "/path/to/file.py", line 51, in <module>
    print(4/0)
ZeroDivisionError: division by zero

Process finished with exit code 0
nu everest
sumber
7
walaupun tidak persis dengan format yang diinginkan oleh op, ini adalah solusi paling sederhana dan paling kuat
cs_alumnus
5
apa yang kuat tentang itu?
jouell
1
@jouell Hei, kadang-kadang saya suka menggunakan kata-kata indah :)
Rishav
Bersih & efektif. Terima kasih telah berbagi :)
Himanshu Gautam
49

Sumber (Py v2.7.3) untuk traceback.format_exception () dan dipanggil / fungsi terkait sangat membantu. Yang memalukan, saya selalu lupa untuk Baca Sumber . Saya hanya melakukannya untuk ini setelah mencari detail serupa dengan sia-sia. Sebuah pertanyaan sederhana, "Bagaimana cara membuat kembali output yang sama dengan Python sebagai pengecualian, dengan semua detail yang sama?" Ini akan membuat siapa pun 90 +% untuk apa pun yang mereka cari. Frustrasi, saya datang dengan contoh ini. Saya harap ini membantu orang lain. (Ini benar-benar membantu saya! ;-)

import sys, traceback

traceback_template = '''Traceback (most recent call last):
  File "%(filename)s", line %(lineno)s, in %(name)s
%(type)s: %(message)s\n''' # Skipping the "actual line" item

# Also note: we don't walk all the way through the frame stack in this example
# see hg.python.org/cpython/file/8dffb76faacc/Lib/traceback.py#l280
# (Imagine if the 1/0, below, were replaced by a call to test() which did 1/0.)

try:
    1/0
except:
    # http://docs.python.org/2/library/sys.html#sys.exc_info
    exc_type, exc_value, exc_traceback = sys.exc_info() # most recent (if any) by default

    '''
    Reason this _can_ be bad: If an (unhandled) exception happens AFTER this,
    or if we do not delete the labels on (not much) older versions of Py, the
    reference we created can linger.

    traceback.format_exc/print_exc do this very thing, BUT note this creates a
    temp scope within the function.
    '''

    traceback_details = {
                         'filename': exc_traceback.tb_frame.f_code.co_filename,
                         'lineno'  : exc_traceback.tb_lineno,
                         'name'    : exc_traceback.tb_frame.f_code.co_name,
                         'type'    : exc_type.__name__,
                         'message' : exc_value.message, # or see traceback._some_str()
                        }

    del(exc_type, exc_value, exc_traceback) # So we don't leave our local labels/objects dangling
    # This still isn't "completely safe", though!
    # "Best (recommended) practice: replace all exc_type, exc_value, exc_traceback
    # with sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

    print
    print traceback.format_exc()
    print
    print traceback_template % traceback_details
    print

Dalam jawaban spesifik untuk pertanyaan ini:

sys.exc_info()[0].__name__, os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename), sys.exc_info()[2].tb_lineno
pythonlarry
sumber
1
ubah 'message' : exc_value.messageke 'message' : str(exc_value)untuk py3
user2682863
34

Berikut adalah contoh yang menunjukkan nomor baris tempat pengecualian terjadi.

import sys
try:
    print(5/0)
except Exception as e:
    print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)

print('And the rest of program continues')
Stryker
sumber