Tangkap beberapa pengecualian dalam satu baris (kecuali blok)

2759

Saya tahu bahwa saya dapat melakukan:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

Saya juga bisa melakukan ini:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

Tetapi jika saya ingin melakukan hal yang sama di dalam dua pengecualian berbeda, yang terbaik yang dapat saya pikirkan saat ini adalah melakukan ini:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

Apakah ada cara saya bisa melakukan sesuatu seperti ini (karena tindakan untuk mengambil dalam kedua pengecualian adalah untuk say please):

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

Sekarang ini benar-benar tidak akan berfungsi, karena cocok dengan sintaks untuk:

try:
    # do something that may fail
except Exception, e:
    # say please

Jadi, upaya saya untuk menangkap dua pengecualian berbeda tidak sepenuhnya berhasil.

Apakah ada cara untuk melakukan ini?

inspectorG4dget
sumber
6
Perhatikan bahwa dalam Python 3, yang terakhir tidak lagi sintaks yang valid.
gerrit

Jawaban:

3726

Dari Dokumentasi Python :

Klausa kecuali dapat menyebutkan beberapa pengecualian sebagai tupel tanda kurung, misalnya

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Atau, hanya untuk Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

Memisahkan pengecualian dari variabel dengan koma masih akan bekerja di Python 2.6 dan 2.7, tetapi sekarang sudah usang dan tidak berfungsi di Python 3; sekarang Anda harus menggunakan as.

mechanical_meat
sumber
9
Saya sudah mencobanya ... dengan a list, dan hasilnya a TypeError. Sepertinya kesalahan harus dalam tupleagar penangkapan berfungsi seperti yang diharapkan.
BallpointBen
4
Mengapa Anda pernah menggunakan daftar ketika Anda melihat dengan jelas bahwa itu didokumentasikan bahwa tuple diperlukan dalam kasus ini?
mechanical_meat
6
Tidak jelas apakah "tanda kurung" hanya sintaksis atau bahwa tupel yang bonafid diperlukan. "Parenthesized" menyesatkan karena Anda dapat membuat tuple tanpa tanda kurung di tempat lain dan kemudian menggunakannya di dalam exceptbaris. Itu hanya perlu dipasangkan jika dibuat dalam exceptbaris.
BallpointBen
5
@ Joseph Bani, bagaimana dengan ekspresi generator?
jammertheprogrammer
12
@JosephBani Itu tidak benar sama sekali. Di 2 + (x * 2), (x * 2)tentu saja bukan tupel. Kurung adalah konstruk pengelompokan umum. Karakteristik yang menentukan dari tuple adalah bahwa ia mengandung koma - lihat dokumentasi Python : "Perhatikan bahwa sebenarnya itu adalah koma yang membuat tuple, bukan tanda kurung."
Soren Bjornstad
314

Bagaimana cara menangkap beberapa pengecualian dalam satu baris (kecuali blok)

Melakukan hal ini:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

Tanda kurung diperlukan karena sintaks lama yang menggunakan koma untuk menetapkan objek kesalahan ke nama. Kata askunci digunakan untuk penugasan. Anda dapat menggunakan nama apa pun untuk objek kesalahan, saya lebih suka errorsecara pribadi.

Praktek terbaik

Untuk melakukan ini dengan cara yang saat ini dan meneruskan yang kompatibel dengan Python, Anda perlu memisahkan Pengecualian dengan koma dan membungkusnya dengan tanda kurung untuk membedakan dari sintaks sebelumnya yang menetapkan instance pengecualian ke nama variabel dengan mengikuti jenis Pengecualian untuk ditangkap dengan koma.

Berikut adalah contoh penggunaan sederhana:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

Saya hanya menetapkan pengecualian ini untuk menghindari menyembunyikan bug, yang jika saya temui saya harapkan jejak stack penuh dari.

Ini didokumentasikan di sini: https://docs.python.org/tutorial/errors.html

Anda dapat menetapkan pengecualian ke variabel, ( eadalah umum, tetapi Anda mungkin lebih suka variabel yang lebih bertele-tele jika Anda memiliki penanganan pengecualian yang lama atau IDE Anda hanya menyoroti pilihan yang lebih besar dari itu, seperti yang saya miliki.) Contoh memiliki atribut args. Berikut ini sebuah contoh:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

Perhatikan bahwa dalam Python 3, errobjek jatuh keluar dari ruang lingkup ketika exceptblok disimpulkan.

Usang

Anda dapat melihat kode yang menetapkan kesalahan dengan koma. Penggunaan ini, satu-satunya formulir yang tersedia di Python 2.5 dan sebelumnya, sudah tidak digunakan lagi, dan jika Anda ingin kode Anda maju kompatibel di Python 3, Anda harus memperbarui sintaks untuk menggunakan formulir baru:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

Jika Anda melihat penetapan nama koma di basis kode Anda, dan Anda menggunakan Python 2.5 atau lebih tinggi, beralihlah ke cara baru untuk melakukannya sehingga kode Anda tetap kompatibel ketika Anda memutakhirkan.

The suppressmanager konteks

Jawaban yang diterima benar-benar 4 baris kode, minimum:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

The try, except, passgaris dapat ditangani dalam satu baris dengan manajer konteks menekan, tersedia dalam Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

Jadi, ketika Anda ingin passpengecualian tertentu, gunakan suppress.

Aaron Hall
sumber
2
Selain itu baik suppress, banyak lebih mudah dibaca daripada hanya melakukan passdiexcept
Mache
50

Dari dokumentasi Python -> 8.3 Menangani Pengecualian :

Sebuah trypernyataan mungkin memiliki lebih dari satu kecuali klausa, untuk menentukan handler untuk pengecualian yang berbeda. Paling banyak satu penangan akan dieksekusi. Penangan hanya menangani pengecualian yang terjadi pada klausa percobaan yang sesuai, bukan pada penangan lain dari pernyataan percobaan yang sama. Klausa kecuali dapat menyebutkan beberapa pengecualian sebagai tupel tanda kurung, misalnya:

except (RuntimeError, TypeError, NameError):
    pass

Perhatikan bahwa tanda kurung di sekitar tupel ini diperlukan, karena kecuali ValueError, e:sintaks yang digunakan untuk apa yang biasanya ditulis except ValueError as e:dalam Python modern (dijelaskan di bawah). Sintaksis lama masih didukung untuk kompatibilitas mundur. Ini berarti except RuntimeError, TypeErrortidak setara dengan except (RuntimeError, TypeError):tetapi except RuntimeError as TypeError:bukan yang Anda inginkan.

fedorqui 'SO berhenti merugikan'
sumber
35

Jika Anda sering menggunakan sejumlah besar pengecualian, Anda dapat menentukan terlebih dahulu tupel, sehingga Anda tidak perlu mengetik ulang berkali-kali.

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

CATATAN:

  1. Jika Anda juga perlu menangkap pengecualian lain selain yang ada dalam tuple yang telah ditentukan sebelumnya, Anda perlu mendefinisikan blok kecuali yang lain.

  2. Jika Anda tidak bisa mentolerir variabel global, tentukan di main () dan bagikan di mana diperlukan ...

kumis putih
sumber
17

Salah satu cara untuk melakukan ini adalah ..

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

dan cara lain adalah membuat metode yang melakukan tugas yang dieksekusi oleh exceptblok dan memanggilnya melalui semua exceptblok yang Anda tulis.

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

Saya tahu bahwa yang kedua bukanlah cara terbaik untuk melakukan ini, tetapi saya hanya menunjukkan sejumlah cara untuk melakukan hal ini.

M. Usman
sumber
Saya menggunakan yang kedua karena saya memiliki dua pengecualian berbeda yang masing-masing harus diproses secara berbeda. Apakah ada yang salah dengan melakukan itu?
majikman
@majikman Metode kedua dengan beberapa klausa yang masing-masing memanggil fungsi yang sama bukanlah yang terbaik ketika Anda mencoba untuk tidak mengulangi diri Anda sendiri dan melakukan hal yang sama untuk dua pengecualian. (Lihat jawaban lain untuk cara yang benar untuk melakukannya). Namun, memiliki beberapa exceptklausa adalah normal ketika Anda ingin menangani pengecualian secara berbeda.
Eponim