Tentang menangkap pengecualian APA SAJA

696

Bagaimana saya bisa menulis blok try/ exceptyang menangkap semua pengecualian?

pengguna469652
sumber
4
Dalam kebanyakan kasus Anda, mungkin, melakukan sesuatu yang salah jika Anda mencoba menangkap pengecualian. Maksud saya Anda bisa saja salah mengeja sesuatu dalam kode Anda dan Anda bahkan tidak akan mengetahuinya. Merupakan praktik yang baik untuk menangkap pengecualian tertentu.
vwvolodya
12
Untuk lebih tepatnya, menangkap semua pengecualian yang mungkin hanya masalah jika mereka ditangkap secara diam-diam. Sulit untuk memikirkan di mana lagi pendekatan ini tepat, selain di mana pesan kesalahan yang tertangkap dicetak sys.stderrdan mungkin dicatat. Itu adalah pengecualian yang benar-benar valid dan umum.
Evgeni Sergeev
apakah kamu mencoba try: whatever() except Exception as e: exp_capture() :?
Charlie Parker

Jawaban:

564

Anda bisa tetapi Anda mungkin tidak boleh:

try:
    do_something()
except:
    print "Caught it!"

Namun, ini juga akan menangkap pengecualian seperti KeyboardInterruptdan Anda biasanya tidak menginginkannya, bukan? Kecuali jika Anda langsung meningkatkan pengecualian - lihat contoh berikut dari dokumen :

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
Tim Pietzcker
sumber
15
Pernyataan terakhir Anda tidak benar, Anda harus secara eksplisit mengatakan except Exception:telanjang kecuali yang Anda miliki di sana juga akan menangkap yang BaseException.
Pykler
7
Anda benar-benar harus mencetak ke stderr.
nyuszika7h
41
Saya sangat sangat tidak setuju dengan pernyataan itu, "seharusnya tidak." Anda harus melakukannya dengan hemat. Ada saat-saat ketika Anda berurusan dengan perpustakaan pihak ketiga (kadang-kadang dimuat secara dinamis !!) yang benar-benar gila dengan pengecualian dan melacak semuanya bisa menjadi tugas yang sangat menyakitkan, dan jika Anda melewatkan satu saja, Anda memiliki yang sangat sangat bug menyakitkan besar di sistem Anda. Yang sedang berkata, ada baiknya untuk melacak sebanyak yang Anda bisa dan menanganinya dengan tepat dan kemudian memiliki cadangan semua untuk yang Anda lewatkan.
Blaze
26
Yang saya temukan juga aneh adalah bahwa dalam bahasa pengetikan bebek di mana Anda tidak mendeklarasikan variabel instan, tiba-tiba sangat khawatir untuk tidak mengetik semua pengecualian Anda. Hmm!
Blaze
834

Terlepas dari except:klausa telanjang (yang seperti yang orang lain katakan tidak boleh Anda gunakan), Anda bisa menangkap Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

Anda biasanya hanya akan mempertimbangkan melakukan ini pada tingkat terluar kode Anda jika misalnya Anda ingin menangani pengecualian yang tidak tertangkap sebelum dihentikan.

Keuntungan except Exceptionlebih dari telanjang exceptadalah bahwa ada beberapa pengecualian yang tidak akan ditangkap, paling jelas KeyboardInterruptdan SystemExit: jika Anda menangkap dan menelannya maka Anda bisa menyulitkan siapa pun untuk keluar dari skrip Anda.

Duncan
sumber
Saya memiliki hal yang sama di pikiran saya, tetapi mereka adalah kerugian, misalkan mereka adalah dua kesalahan ketika sekali tertangkap dan dan kecuali Anda hanya mencetak Anda akan keluar dari blok percobaan dan Anda tidak akan pernah tahu kesalahan kedua .. .
6
Bagi siapa pun yang bertanya-tanya, sangat bertentangan dengan harapan saya, ini masih akan menangkap hal-hal non-pengecualian seperti int, setidaknya dalam python 2.x.
Joseph Garvin
5
@ JosephephGarvin, itu tidak benar, yaitu ini tidak akan menangkap "non-pengecualian" yang tidak subkelas Exception. Perhatikan bahwa tidak mungkin untuk menaikkan intpengecualian, dan mencoba melakukannya menimbulkan TypeErrorpengecualian, yang akan ditangkap oleh except Exceptionklausa terlampir dalam kasus seperti itu. Di sisi lain, kelas gaya lama dapat dinaikkan dan dikualifikasikan sebagai "non-pengecualian" yang tidak subkelas Exception- ini akan ditangkap oleh exceptklausa telanjang tetapi tidak oleh except Exceptionklausa.
Yoel
4
@JosephGarvin memeriksa entri blog ini: chris-lamb.co.uk/posts/no-one-expects-string-literal-exception Saya dengan @Yoel untuk yang satu ini, pengujian Anda baru saja menutupiTypeError
Duncan
2
@CharlieParker tidak ada salahnya menangkap mereka jika itu yang Anda inginkan tetapi kebanyakan tidak. Memanggil sys.exit()biasanya berarti Anda mengharapkan aplikasi untuk berhenti tetapi jika Anda menangkap SystemExit tidak akan. Demikian juga jika Anda menekan control-C pada skrip yang sedang berjalan (Ctrl-break pada windows) Anda mengharapkan program untuk berhenti, tidak untuk menangkap kesalahan dan terus berjalan. Tetapi Anda dapat menangkap salah satu dari keduanya jika ingin melakukan pembersihan sebelum ada.
Duncan
100

Anda dapat melakukan ini untuk menangani pengecualian umum

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message
vwvolodya
sumber
8
Ini mungkin tidak menangkap semua pengecualian, karena kelas dasar untuk semua pengecualian adalah BaseException dan saya telah menemukan kode produksi yang tidak ada dalam keluarga kelas Exception. Lihat docs.python.org/3/library/… untuk detail tentang ini.
DDay
4
Ini tidak mencakup semua pengecualian.
Andy_A̷n̷d̷y̷
6
Secara teknis, ia harus menangkap semua pengecualian yang tidak keluar dari sistem. Dari docs @DDay ditautkan: " exception BaseException: Kelas dasar untuk semua pengecualian bawaan. Ini tidak dimaksudkan untuk diwarisi langsung oleh kelas yang ditentukan pengguna (untuk itu, gunakan Pengecualian)." Kecuali Anda bekerja dengan kode yang mengabaikan ini, atau Anda perlu menangkap pengecualian yang keluar dari sistem, hal di atas tidak masalah untuk digunakan.
Peter Cassetta
@PeterCassetta kapan seseorang ingin menangkap pengecualian sistem? Tampaknya ada kesamaan dalam pertanyaan bahwa kita tidak ingin menangkap ini, tetapi saya tidak mengerti mengapa. Kenapa tidak biasanya?
Charlie Parker
68

Untuk menangkap semua pengecualian yang mungkin, tangkap BaseException. Itu di atas hierarki Pengecualian:

Python 3: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7: https://docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

Tetapi seperti yang disebutkan orang lain, Anda biasanya tidak memerlukan ini, hanya untuk kasus tertentu.

gitaarik
sumber
1
Apakah ingin menyimpan progres pekerjaan lama setelah menekan Ctrl-C yang tidak biasa?
BallpointBen
54

Contoh yang sangat sederhana, mirip dengan yang ditemukan di sini:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

Jika Anda mencoba untuk menangkap SEMUA pengecualian, maka letakkan semua kode Anda dalam pernyataan "coba:", sebagai ganti 'cetak "Melakukan tindakan yang dapat menimbulkan pengecualian."'.

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

Dalam contoh di atas, Anda akan melihat output dalam urutan ini:

1) Melakukan tindakan yang dapat menimbulkan pengecualian.

2) Akhirnya dipanggil langsung setelah menjalankan pernyataan coba apakah pengecualian dilemparkan atau tidak.

3) "Sebuah pengecualian dilemparkan!" atau "Semuanya tampak hebat!" tergantung pada apakah pengecualian dilemparkan.

Semoga ini membantu!

Joshua Burns
sumber
26

Ada beberapa cara untuk melakukan ini khususnya dengan Python 3.0 dan di atasnya

Pendekatan 1

Ini adalah pendekatan sederhana tetapi tidak direkomendasikan karena Anda tidak akan tahu persis baris kode mana yang benar-benar melempar pengecualian:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Pendekatan 2

Pendekatan ini direkomendasikan karena memberikan lebih banyak detail tentang setiap pengecualian. Itu termasuk:

  • Nomor baris untuk kode Anda
  • Nama file
  • Kesalahan aktual dengan cara yang lebih verbose

Satu-satunya kelemahan adalah tracback perlu diimpor.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()
grepit
sumber
21

Saya baru saja menemukan trik kecil ini untuk menguji apakah nama pengecualian di Python 2.7. Terkadang saya telah menangani pengecualian khusus dalam kode, jadi saya perlu tes untuk melihat apakah nama itu ada dalam daftar pengecualian yang ditangani.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception
Danilo
sumber
2
try:
    whatever()
except:
    # this will catch any exception or error

Perlu disebutkan ini bukan pengkodean Python yang tepat. Ini juga akan menangkap banyak kesalahan yang mungkin tidak ingin Anda tangkap.

Yuval Adam
sumber
gunakan saja kecuali jangan cach semua pengecualian seperti disebutkan dalam beberapa jawaban lain. Anda harus menggunakan BaseException untuk tujuan ini, tetapi seperti yang Anda katakan, tidak ada yang harus menangkap semua pengecualian seperti ini. Saya kira tidak apa-apa untuk memulai jika tujuannya adalah untuk menambahkan lebih banyak butiran kecuali selama pengembangan tetapi saya tidak berpikir itu akan menjadi ...
Pyglouthon