Jawaban:
Bagaimana cara saya melempar / menaikkan pengecualian secara manual dengan Python?
Gunakan konstruktor Pengecualian yang paling spesifik yang secara semantik cocok dengan masalah Anda .
Spesifik dalam pesan Anda, misalnya:
raise ValueError('A very specific bad thing happened.')
Hindari membesarkan obat generik Exception
. Untuk menangkapnya, Anda harus menangkap semua pengecualian lain yang lebih spesifik yang mensubklasifikasikannya.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Sebagai contoh:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Dan tangkapan yang lebih spesifik tidak akan menangkap pengecualian umum:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
raise
pernyataanraise ValueError('A very specific bad thing happened')
yang juga dengan mudah memungkinkan sejumlah argumen sewenang-wenang untuk diteruskan ke konstruktor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Argumen ini diakses oleh args
atribut pada Exception
objek. Sebagai contoh:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
cetakan
('message', 'foo', 'bar', 'baz')
Dalam Python 2.5, message
atribut yang sebenarnya ditambahkan untuk BaseException
mendorong pengguna ke subkelas Pengecualian dan berhenti menggunakan args
, tetapi pengenalan message
dan penghentian arg yang asli telah ditarik kembali .
except
klausaSaat berada di dalam klausa kecuali, Anda mungkin ingin, misalnya, mencatat bahwa jenis kesalahan tertentu terjadi, dan kemudian naik kembali. Cara terbaik untuk melakukan ini sambil menjaga jejak stack adalah dengan menggunakan pernyataan kenaikan gaji. Sebagai contoh:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Anda dapat mempertahankan stacktrace (dan nilai kesalahan) dengan sys.exc_info()
, tapi ini cara yang lebih rentan kesalahan dan memiliki masalah kompatibilitas antara Python 2 dan 3 , lebih suka menggunakan telanjang raise
untuk menaikkan kembali.
Untuk menjelaskan - sys.exc_info()
mengembalikan jenis, nilai, dan traceback.
type, value, traceback = sys.exc_info()
Ini adalah sintaks dalam Python 2 - perhatikan ini tidak kompatibel dengan Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Jika Anda mau, Anda dapat mengubah apa yang terjadi dengan kenaikan gaji baru Anda - mis. Pengaturan baru args
untuk instance:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
Dan kami telah melestarikan seluruh traceback sambil memodifikasi argumen. Perhatikan bahwa ini bukan praktik terbaik dan ini adalah sintaks yang tidak valid di Python 3 (membuat menjaga kompatibilitas jauh lebih sulit untuk diselesaikan).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
Dengan Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Sekali lagi: hindari memanipulasi traceback secara manual. Itu kurang efisien dan lebih rentan kesalahan. Dan jika Anda menggunakan threading dan sys.exc_info
Anda bahkan mungkin mendapatkan traceback yang salah (terutama jika Anda menggunakan penanganan pengecualian untuk aliran kontrol - yang secara pribadi saya cenderung hindari.)
Di Python 3, Anda bisa membuat rantai Pengecualian, yang mempertahankan traceback:
raise RuntimeError('specific message') from error
Waspadalah:
Ini dapat dengan mudah disembunyikan dan bahkan masuk ke kode produksi. Anda ingin mengajukan pengecualian, dan melakukannya akan memunculkan pengecualian, tetapi bukan yang dimaksudkan!
Berlaku di Python 2, tetapi tidak dalam Python 3 adalah sebagai berikut:
raise ValueError, 'message' # Don't do this, it's deprecated!
Hanya valid dalam versi Python yang jauh lebih lama (2.4 dan lebih rendah), Anda mungkin masih melihat orang-orang yang meningkatkan string:
raise 'message' # really really wrong. don't do this.
Di semua versi modern, ini sebenarnya akan menaikkan a TypeError
, karena Anda tidak menaikkan BaseException
jenis. Jika Anda tidak memeriksa pengecualian yang tepat dan tidak memiliki pengulas yang mengetahui masalah ini, itu bisa mulai diproduksi.
Saya mengajukan Pengecualian untuk memperingatkan konsumen tentang API saya jika mereka salah menggunakannya:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
"Aku ingin membuat kesalahan dengan sengaja, sehingga akan masuk ke pengecualian"
Anda dapat membuat jenis kesalahan Anda sendiri, jika Anda ingin menunjukkan sesuatu yang spesifik salah dengan aplikasi Anda, cukup subkelas poin yang sesuai dalam hierarki pengecualian:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
dan penggunaan:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
tampaknya melakukan apa yang saya inginkan, dan saya tidak pernah mengalami masalah dengannya. Tapi rasanya berantakan, dan bukan praktik yang diterima. Apakah ada cara yang lebih baik?
Exception
sebagai kelas induk Anda - Anda dapat mensubklasifikasikan sesuatu yang lebih spesifik, dan harus melakukannya jika itu masuk akal.
AppError
pengecualian yang tidak ditentukan . Mungkin lebih baik menggunakan kesalahan AttributeError
JANGAN LAKUKAN INI . Mengangkat telanjang
Exception
sama sekali bukan hal yang benar untuk dilakukan; lihat jawaban Aaron Hall sebagai gantinya.
Tidak bisa mendapatkan lebih banyak pythonic dari ini:
raise Exception("I know python!")
Lihat dokumen pernyataan kenaikan untuk python jika Anda ingin info lebih lanjut.
Di Python3 ada 4 sintaks yang berbeda untuk rasing pengecualian:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. meningkatkan pengecualian vs 2. meningkatkan pengecualian (args)
Jika Anda menggunakan raise exception (args)
untuk menaikkan pengecualian maka args
akan dicetak ketika Anda mencetak objek pengecualian - seperti yang ditunjukkan pada contoh di bawah ini.
#raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3. naik
raise
pernyataan tanpa argumen kembali memunculkan pengecualian terakhir. Ini berguna jika Anda perlu melakukan beberapa tindakan setelah menangkap pengecualian dan kemudian ingin menaikkannya kembali. Tetapi jika tidak ada pengecualian sebelumnya, raise
pernyataan menimbulkan TypeError
Pengecualian.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. meningkatkan exception (args) dari original_exception
Pernyataan ini digunakan untuk membuat rantai pengecualian di mana pengecualian yang dimunculkan sebagai respons terhadap pengecualian lain dapat berisi detail pengecualian asli - seperti yang ditunjukkan dalam contoh di bawah ini.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Keluaran:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
exception(args)
lebihexception (args)
raise exception(args) from None
mengatakan bahwa pengecualian aktif saat ini ditangani dan tidak lagi menarik. Kalau tidak, jika Anda menaikkan pengecualian di dalam except
blok dan itu tidak ditangani, traceback untuk kedua pengecualian akan ditampilkan dipisahkan oleh pesan "Selama menangani pengecualian di atas, pengecualian lain terjadi"
Untuk kasus umum di mana Anda perlu melempar pengecualian sebagai tanggapan terhadap beberapa kondisi yang tidak terduga, dan bahwa Anda tidak pernah berniat untuk menangkap, tetapi hanya gagal cepat untuk memungkinkan Anda men-debug dari sana jika itu terjadi - yang paling logis tampaknya adalah AssertionError
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
ValueError
daripada AssertionError
karena tidak ada masalah dengan pernyataan (karena tidak ada yang dibuat di sini) - masalahnya adalah dengan nilai. Jika Anda benar-benar menginginkannya AssertionError
, tulislah assert distance > 0, 'Distance must be positive'
. Tetapi Anda tidak boleh salah memeriksa seperti itu karena pernyataan dapat dimatikan ( python -O
).
-O
.
Baca jawaban yang ada terlebih dahulu, ini hanya sebuah tambahan.
Perhatikan bahwa Anda dapat mengajukan pengecualian dengan atau tanpa argumen.
Contoh:
raise SystemExit
keluar dari program tetapi Anda mungkin ingin tahu apa yang terjadi. Jadi Anda dapat menggunakan ini.
raise SystemExit("program exited")
ini akan mencetak "program keluar" ke stderr sebelum menutup program.
raise SystemExit()
itu pilihan yang lebih baik? Mengapa yang pertama bekerja?
Cara lain untuk melempar pengecualian adalah assert
. Anda dapat menggunakan menegaskan untuk memverifikasi suatu kondisi sedang dipenuhi jika tidak maka itu akan naik AssertionError
. Untuk lebih jelasnya lihat di sini .
def avg(marks):
assert len(marks) != 0,"List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))
Hanya untuk diketahui: ada saatnya Anda DO ingin menangani pengecualian umum. Jika Anda memproses banyak file dan mencatat kesalahan Anda, Anda mungkin ingin mengetahui kesalahan apa pun yang terjadi pada suatu file, mencatatnya, dan melanjutkan memproses sisa file tersebut. Dalam hal ini, a
try:
foo()
except Exception as e:
print(str(e)) # Print out handled error
memblokir cara yang baik untuk melakukannya. Anda masih ingin raise
pengecualian khusus sehingga Anda tahu apa artinya.
Anda harus mempelajari pernyataan kenaikan python untuk itu. Itu harus disimpan di dalam blok percobaan. Contoh -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
raise
adalah apa yang saya butuhkan untuk dapat melakukan debugging kesalahan kustom pada beberapa tingkat eksekusi kode tanpa melanggar jejak tumpukan.