Saya ingin mencapai sesuatu seperti ini:
def foo():
try:
raise IOError('Stuff ')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
e.message = e.message + 'happens at %s' % arg1
raise
bar('arg1')
Traceback...
IOError('Stuff Happens at arg1')
Tapi yang saya dapatkan adalah:
Traceback..
IOError('Stuff')
Ada petunjuk tentang bagaimana mencapai ini? Bagaimana cara melakukannya dengan Python 2 dan 3?
message
atribut Exception, saya menemukan pertanyaan SO ini, BaseException.message tidak digunakan lagi di Python 2.6 , yang tampaknya menunjukkan penggunaannya sekarang tidak disarankan (dan mengapa tidak ada di dokumen).Jawaban:
Saya akan melakukannya seperti ini sehingga mengubah jenisnya
foo()
tidak perlu juga mengubahnyabar()
.def foo(): try: raise IOError('Stuff') except: raise def bar(arg1): try: foo() except Exception as e: raise type(e)(e.message + ' happens at %s' % arg1) bar('arg1')
Perbarui 1
Berikut ini sedikit modifikasi yang mempertahankan traceback asli:
... def bar(arg1): try: foo() except Exception as e: import sys raise type(e), type(e)(e.message + ' happens at %s' % arg1), sys.exc_info()[2] bar('arg1')
Perbarui 2
Untuk Python 3.x, kode update pertama saya adalah sintaksis benar ditambah gagasan memiliki
message
atribut padaBaseException
itu ditarik dalam perubahan ke PEP 352 pada 2012/05/16 (update pertama saya telah diposting pada 2012-03-12) . Jadi saat ini, dengan Python 3.5.2, Anda perlu melakukan sesuatu di sepanjang baris ini untuk mempertahankan traceback dan bukan hardcode jenis pengecualian dalam fungsibar()
. Perhatikan juga bahwa akan ada baris:di pesan traceback ditampilkan.
# for Python 3.x ... def bar(arg1): try: foo() except Exception as e: import sys raise type(e)(str(e) + ' happens at %s' % arg1).with_traceback(sys.exc_info()[2]) bar('arg1')
Perbarui 3
Sebuah commenter bertanya apakah ada cara yang akan bekerja di kedua Python 2 dan 3. Meskipun jawabannya mungkin tampaknya menjadi "Tidak" karena perbedaan sintaks, ada adalah cara sekitar bahwa dengan menggunakan fungsi pembantu seperti
reraise()
disix
add pada modul. Jadi, jika Anda lebih suka tidak menggunakan pustaka karena alasan tertentu, di bawah ini adalah versi mandiri yang disederhanakan.Perhatikan juga, bahwa karena pengecualian dijalankan ulang dalam
reraise()
fungsi, itu akan muncul di traceback apa pun yang dimunculkan, tetapi hasil akhirnya adalah yang Anda inginkan.import sys if sys.version_info.major < 3: # Python 2? # Using exec avoids a SyntaxError in Python 3. exec("""def reraise(exc_type, exc_value, exc_traceback=None): raise exc_type, exc_value, exc_traceback""") else: def reraise(exc_type, exc_value, exc_traceback=None): if exc_value is None: exc_value = exc_type() if exc_value.__traceback__ is not exc_traceback: raise exc_value.with_traceback(exc_traceback) raise exc_value def foo(): try: raise IOError('Stuff') except: raise def bar(arg1): try: foo() except Exception as e: reraise(type(e), type(e)(str(e) + ' happens at %s' % arg1), sys.exc_info()[2]) bar('arg1')
sumber
__str__
, Anda mungkin mendapatkan hasil yang tidak diinginkan. Perhatikan juga bahwa argumen kedua diteruskan ke konstruktor yang diberikan oleh argumen pertama, yang menghasilkan argumen yang agak tidak masuk akaltype(e)(type(e)(e.message)
. Ketiga, e.message tidak digunakan lagi dan mendukung e.args [0].Jika Anda datang ke sini mencari solusi untuk Python 3 , manualnya mengatakan:
raise new_exc from original_exc
Contoh:
try: return [permission() for permission in self.permission_classes] except TypeError as e: raise TypeError("Make sure your view's 'permission_classes' are iterable. " "If you use '()' to generate a set with a single element " "make sure that there is a comma behind the one (element,).") from e
Yang terlihat seperti ini pada akhirnya:
Mengubah sebuah pesan yang benar-benar tidak mendeskripsikan
TypeError
menjadi pesan yang bagus dengan petunjuk menuju solusi tanpa mengacaukan Pengecualian asli.sumber
e.args
, tapi itu Tuple, jadi tidak bisa diubah. Jadi pertama-tama salinargs
ke dalam daftar, lalu modifikasi, lalu salin kembali sebagai Tuple:args = list(e.args)
args[0] = 'bar'
e.args = tuple(args)
Dengan asumsi Anda tidak ingin atau tidak dapat memodifikasi foo (), Anda dapat melakukan ini:
try: raise IOError('stuff') except Exception as e: if len(e.args) >= 1: e.args = (e.args[0] + ' happens',) + e.args[1:] raise
Ini memang satu-satunya solusi di sini yang memecahkan masalah dengan Python 3 tanpa pesan "Selama menangani pengecualian di atas, terjadi pengecualian lain" yang jelek dan membingungkan.
Dalam hal garis re penggalangan harus ditambahkan ke stack trace, menulis
raise e
bukanraise
akan melakukan trik.sumber
e.args = ('mynewstr' + e.args[0],) + e.args[1:]
Sejauh ini saya tidak menyukai semua jawaban yang diberikan. Mereka masih terlalu bertele-tele. Baik dalam kode dan keluaran pesan.
Yang ingin saya miliki hanyalah stacktrace yang menunjuk ke pengecualian sumber, tidak ada pengecualian di antaranya, jadi tidak ada pembuatan pengecualian baru, hanya menaikkan yang asli dengan semua status bingkai tumpukan yang relevan di dalamnya, yang mengarah ke sana.
Steve Howard memberikan jawaban yang bagus yang ingin saya perpanjang, tidak, kurangi ... hanya menjadi python 3.
except Exception as e: e.args = ("Some failure state", *e.args) raise
Satu-satunya hal baru adalah parameter expansion / unpacking yang membuatnya kecil dan cukup mudah untuk saya gunakan.
Cobalah:
foo = None try: try: state = "bar" foo.append(state) except Exception as e: e.args = ("Appending '"+state+"' failed", *e.args) raise print(foo[0]) # would raise too except Exception as e: e.args = ("print(foo) failed: " + str(foo), *e.args) raise
Ini akan memberi Anda:
Traceback (most recent call last): File "test.py", line 6, in <module> foo.append(state) AttributeError: ('print(foo) failed: None', "Appending 'bar' failed", "'NoneType' object has no attribute 'append'")
Sebuah cetakan cantik yang sederhana bisa seperti itu
print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
sumber
Salah satu pendekatan praktis yang saya gunakan adalah menggunakan atribut class sebagai penyimpanan untuk detail, karena atribut class dapat diakses dari objek kelas dan instance kelas:
class CustomError(Exception): def __init__(self, details: Dict): self.details = details
Kemudian di kode Anda:
raise CustomError({'data': 5})
Dan saat menemukan kesalahan:
except CustomError as e: # Do whatever you want with the exception instance print(e.details)
sumber
Saya akan memberikan potongan kode yang sering saya gunakan setiap kali saya ingin menambahkan info tambahan ke pengecualian. Saya bekerja dengan Python 2.7 dan 3.6.
import sys import traceback try: a = 1 b = 1j # The line below raises an exception because # we cannot compare int to complex. m = max(a, b) except Exception as ex: # I create my informational message for debugging: msg = "a=%r, b=%r" % (a, b) # Gather the information from the original exception: exc_type, exc_value, exc_traceback = sys.exc_info() # Format the original exception for a nice printout: traceback_string = ''.join(traceback.format_exception( exc_type, exc_value, exc_traceback)) # Re-raise a new exception of the same class as the original one, # using my custom message and the original traceback: raise type(ex)("%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % (msg, traceback_string))
Kode di atas menghasilkan keluaran sebagai berikut:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-6-09b74752c60d> in <module>() 14 raise type(ex)( 15 "%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % ---> 16 (msg, traceback_string)) TypeError: a=1, b=1j ORIGINAL TRACEBACK: Traceback (most recent call last): File "<ipython-input-6-09b74752c60d>", line 7, in <module> m = max(a, b) # Cannot compare int to complex TypeError: no ordering relation is defined for complex numbers
Saya tahu ini sedikit menyimpang dari contoh yang diberikan dalam pertanyaan, tetapi saya berharap seseorang menganggapnya berguna.
sumber
Tidak seperti jawaban sebelumnya, ini berfungsi saat menghadapi pengecualian dengan sangat buruk
__str__
. Itu memang memodifikasi jenisnya, untuk memfaktorkan__str__
implementasi yang tidak membantu .Saya masih ingin menemukan peningkatan tambahan yang tidak mengubah jenisnya.
from contextlib import contextmanager @contextmanager def helpful_info(): try: yield except Exception as e: class CloneException(Exception): pass CloneException.__name__ = type(e).__name__ CloneException.__module___ = type(e).__module__ helpful_message = '%s\n\nhelpful info!' % e import sys raise CloneException, helpful_message, sys.exc_traceback class BadException(Exception): def __str__(self): return 'wat.' with helpful_info(): raise BadException('fooooo')
Traceback asli dan jenis (nama) dipertahankan.
Traceback (most recent call last): File "re_raise.py", line 20, in <module> raise BadException('fooooo') File "/usr/lib64/python2.6/contextlib.py", line 34, in __exit__ self.gen.throw(type, value, traceback) File "re_raise.py", line 5, in helpful_info yield File "re_raise.py", line 20, in <module> raise BadException('fooooo') __main__.BadException: wat. helpful info!
sumber
Anda dapat menentukan pengecualian Anda sendiri yang mewarisi dari yang lain dan membuat konstruktornya sendiri untuk menetapkan nilai.
Sebagai contoh:
class MyError(Exception): def __init__(self, value): self.value = value Exception.__init__(self) def __str__(self): return repr(self.value)
sumber
message
pengecualian asli (tapi bisa diperbaiki, saya pikir).Mungkin
except Exception as e: raise IOError(e.message + 'happens at %s'%arg1)
sumber