Bagaimana cara menyimpan nilai traceback / sys.exc_info () dalam variabel?

127

Saya ingin menyimpan nama kesalahan dan detail pelacakan kembali ke dalam variabel. Ini usahaku.

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

Keluaran:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

Output yang diinginkan:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

PS Saya tahu ini dapat dilakukan dengan mudah menggunakan modul traceback, tetapi saya ingin mengetahui penggunaan objek sys.exc_info () [2] di sini.

codersofthedark
sumber
Apakah Anda mencoba mencetak sys.exc_info () [x] .__ str __ ()?
zmbq
3
Anda mungkin telah salah paham tentang apa yang terjadi dalam program Anda: apa yang Anda sebut sebagai "sys.exc_info () [2] object" adalah turunan dari objek traceback (= Anda sudah menggunakan modul traceback). Sekarang, Anda dapat memanipulasi objek itu tanpa menggunakan fungsi helper di modul traceback, tetapi itu tidak mengubah fakta bahwa Anda masih menggunakannya. :)
mac
1
Jadi @mac tolong bantu saya menggunakan mengakses nilai dari objek ini dengan atau tanpa menggunakan fungsi helper.
codersofthedark
1
@dragosrsupercool - Seperti yang saya sebutkan dalam jawaban saya di bawah, Anda harus melihat dokumentasi traceback . Saya memberikan contoh bagaimana mengambil data secara tekstual, tetapi ada metode lain dari objek yang memungkinkan Anda untuk mengekstrak nama pengecualian, baris kode, dll ... yang benar sangat tergantung pada bagaimana Anda ingin memanipulasi nilai setelah itu ...
mac
1
Jawaban saya untuk pertanyaan lain dapat membantu menggambarkan detailnya - dengan tautan! Untuk string terekam, modul pelacakan pustaka standar tampaknya baik-baik saja. Jika Anda ingin mendapatkan detailnya, baca source ( <python install path>/Lib/traceback.py) untuk info lebih lanjut.
pythonlarry

Jawaban:

180

Inilah cara saya melakukannya:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

Namun Anda harus melihat dokumentasi traceback , karena Anda mungkin menemukan metode yang lebih cocok, tergantung bagaimana Anda ingin memproses variabel Anda setelahnya ...

Mac
sumber
1
Saya mencari metode tanpa menggunakan modul traceback. Adakah cara agar kita bisa mencetak detail jejak-kembali dari referensi objek ini? sys.exc_info () [2]
pembuat kode
Benar, itulah mengapa saya pikir kita bisa melakukan sesuatu seperti sys.exc_info () [2] .format_exc (), tetapi ini tidak berhasil .. Jadi, saya bertanya-tanya bagaimana saya bisa mengekstrak nilai dari objek jejak-kembali sys.exc_info () [2]. Ada ide?
codersofthedark
1
sys.exc_info () [2] .tb_text memberikan kesalahan mengikuti -> AttributeError: objek 'traceback' tidak memiliki atribut 'tb_text'
codersofthedark
4
@dragosrsupercool - sys.exc_info()[2].tb_frame.f_code.co_names[3], tetapi sama sekali tidak masuk akal ... Jika ada modul yang dipanggil tracebackdi pustaka standar, ada alasan untuk itu ... :)
mac
2
@codersofthedark traceback.format_exception(*sys.exc_info())adalah cara untuk melakukannya. Tapi itu secara fungsional setara dengan traceback.format_exc().
wizzwizz4
25

sys.exc_info () mengembalikan tupel dengan tiga nilai (tipe, nilai, traceback).

  1. Di sini tipe mendapatkan tipe pengecualian dari Exception yang ditangani
  2. nilai adalah argumen yang diteruskan ke konstruktor kelas pengecualian
  3. traceback berisi informasi tumpukan seperti di mana pengecualian terjadi, dll.

Sebagai Contoh, Dalam program berikut

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

Sekarang Jika kita mencetak tupel nilainya akan menjadi ini.

  1. nilai exc_tuple [0] akan menjadi " ZeroDivisionError "
  2. exc_tuple [1] nilai akan menjadi " pembagian integer atau modulo oleh nol " (String diteruskan sebagai parameter ke kelas pengecualian)
  3. exc_tuple [2] nilai akan menjadi " objek trackback di (beberapa alamat memori) "

Detail di atas juga dapat diambil hanya dengan mencetak pengecualian dalam format string.

print str(e)
keya
sumber
Untuk Python3, exc_tuple [1] (nilai alias) adalah turunan dari pengecualian, bukan "String yang diteruskan sebagai parameter". Lihat: docs.python.org/3/library/sys.html#sys.exc_info
Jinghao Shi
Bukankah seharusnya "kecuali Exception as e:"?
Henrik
20

Gunakan traceback.extract_stack()jika Anda ingin akses mudah ke nama modul dan fungsi serta nomor baris.

Gunakan ''.join(traceback.format_stack())jika Anda hanya menginginkan string yang terlihat seperti traceback.print_stack()output.

Perhatikan bahwa bahkan dengan ''.join()Anda akan mendapatkan string multi-baris, karena elemen format_stack()berisi \n. Lihat keluaran di bawah.

Ingatlah untuk import traceback.

Berikut keluaran dari traceback.extract_stack(). Pemformatan ditambahkan agar mudah dibaca.

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

Berikut keluaran dari ''.join(traceback.format_stack()). Pemformatan ditambahkan agar mudah dibaca.

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'
Nathan
sumber
4

Berhati-hatilah saat Anda mengambil objek pengecualian atau objek pelacakan balik dari pengendali pengecualian, karena ini menyebabkan referensi melingkar dan gc.collect()akan gagal dikumpulkan. Ini tampaknya menjadi masalah khusus di lingkungan notebook ipython / jupyter di mana objek traceback tidak dibersihkan pada waktu yang tepat dan bahkan panggilan eksplisit ke gc.collect()dalam finallybagian tidak melakukan apa pun. Dan itu masalah besar jika Anda memiliki beberapa objek besar yang tidak mendapatkan memori mereka kembali karena itu (misalnya CUDA keluar dari pengecualian memori yang tanpa solusi ini memerlukan kernel restart lengkap untuk memulihkan).

Secara umum, jika Anda ingin menyimpan objek traceback, Anda perlu menghapusnya dari referensi ke locals(), seperti:

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

Dalam kasus notebook jupyter, Anda harus melakukannya setidaknya di dalam penangan pengecualian:

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

Diuji dengan python 3.7.

ps masalah dengan ipython atau jupyter notebook env adalah bahwa ia memiliki %tbsihir yang menyimpan traceback dan membuatnya tersedia kapan saja nanti. Dan sebagai hasilnya, locals()semua frame yang berpartisipasi dalam traceback tidak akan dibebaskan hingga notebook keluar atau pengecualian lain akan menimpa backtrace yang disimpan sebelumnya. Ini sangat bermasalah. Seharusnya tidak menyimpan traceback tanpa membersihkan bingkainya. Perbaikan dikirimkan di sini .

stason
sumber
3

Objek dapat digunakan sebagai parameter dalam Exception.with_traceback()fungsi:

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
Hansen D'Silva
sumber