Cara mengabaikan pengecualian dengan benar

777

Saat Anda hanya ingin mencoba-kecuali tanpa menangani pengecualian, bagaimana Anda melakukannya dengan Python?

Apakah mengikuti cara yang benar untuk melakukannya?

try:
    shutil.rmtree(path)
except:
    pass
Joan Venge
sumber
10
Aneh bahwa tidak ada yang menyebutkannya sampai sekarang (saya lakukan dalam jawaban saya), tetapi untuk fungsi khusus ini, Anda bisa melakukannya shutil.rmtree(path, ignore_errors=True). Namun, ini tidak berlaku untuk sebagian besar fungsi.
Aaron Hall
9
Penting dibaca ketika berpikir untuk mengabaikan pengecualian: Mengapa "kecuali: lulus" praktik pemrograman yang buruk?
colek
3
Bayangkan melakukan ini dalam kehidupan nyata. coba: get_cash ('$ 1000') kecuali: pass # meh, mungkin akan baik
Grokodile
Kehidupan nyata:try: rob() except: run()
PatrickT

Jawaban:

1039
try:
    doSomething()
except: 
    pass

atau

try:
    doSomething()
except Exception: 
    pass

Perbedaannya adalah bahwa yang pertama juga akan menangkap KeyboardInterrupt, SystemExitdan hal-hal seperti itu, yang berasal langsung dari exceptions.BaseException, bukan exceptions.Exception.

Lihat dokumentasi untuk detail:

vartec
sumber
4
Perhatikan bahwa StopIteration dan Warning keduanya juga diturunkan dari Exception. Bergantung pada kebutuhan Anda, Anda mungkin ingin mewarisi dari StandardError sebagai gantinya.
Ben Blank
1
Ini benar, tetapi jika Anda tidak hati-hati, Anda dapat menemukan bug yang halus (terutama jika Anda melakukan sesuatu selain meneruskan StopIteration).
Jason Baker
17
-1, try: shuti.rmtree(...) except: passakan secara kasar menekan kesalahan (bahkan jika Anda salah mengeja shutilmenghasilkan NameError) - setidaknya lakukanexcept OSError:
dbr
44
Jawaban ini, meskipun informatif, tidak memiliki informasi penting - Anda tidak boleh menangkap pengecualian dengan cara ini. Sebagai gantinya, Anda harus selalu mencoba menangkap hanya pengecualian yang Anda pedulikan, jika tidak, Anda akan mengalami mimpi buruk ketika memburu bug sepele, disembunyikan oleh generik "kecuali" Anda. Lihat jawaban dbr untuk info lebih lanjut. (Saya tahu ini bukan pertanyaan awal - tetapi siapa pun yang mencari ini hanya akan mengambil cuplikan Anda dan menggunakannya sebagaimana
mestinya
139

Biasanya dianggap praktik terbaik untuk hanya menangkap kesalahan yang Anda minati. Dalam hal shutil.rmtreeini mungkin OSError:

>>> shutil.rmtree("/fake/dir")
Traceback (most recent call last):
    [...]
OSError: [Errno 2] No such file or directory: '/fake/dir'

Jika Anda ingin mengabaikan kesalahan itu secara diam-diam, lakukan:

try:
    shutil.rmtree(path)
except OSError:
    pass

Mengapa? Katakanlah Anda (entah bagaimana) secara tidak sengaja melewatkan fungsi integer alih-alih sebuah string, seperti:

shutil.rmtree(2)

Ini akan memberikan kesalahan "TypeError: memaksa ke Unicode: perlu string atau buffer, int ditemukan" - Anda mungkin tidak ingin mengabaikan itu, yang bisa sulit untuk debug.

Jika Anda benar - benar ingin mengabaikan semua kesalahan, tangkap Exceptiondaripada except:pernyataan kosong . Lagi-lagi mengapa?

Tidak menentukan pengecualian menangkap setiap pengecualian, termasuk SystemExitpengecualian yang misalnya sys.exit()menggunakan:

>>> try:
...     sys.exit(1)
... except:
...     pass
... 
>>>

Bandingkan ini dengan yang berikut, yang keluar dengan benar:

>>> try:
...     sys.exit(1)
... except Exception:
...     pass
... 
shell:~$ 

Jika Anda ingin menulis kode perilaku yang lebih baik, OSErrorpengecualian dapat mewakili berbagai kesalahan, tetapi dalam contoh di atas kami hanya ingin mengabaikannya Errno 2, sehingga kami bisa lebih spesifik:

import errno

try:
    shutil.rmtree(path)
except OSError as e:
    if e.errno != errno.ENOENT:
        # ignore "No such file or directory", but re-raise other errors
        raise
dbr
sumber
1
shutil.rmtreebukan contoh terbaik, karena Anda hanya akan menggunakan ignore_errors=Trueuntuk fungsi itu ..
wim
113

Ketika Anda hanya ingin melakukan tangkapan mencoba tanpa menangani pengecualian, bagaimana Anda melakukannya dengan Python?

Itu tergantung pada apa yang Anda maksud dengan "penanganan."

Jika Anda bermaksud menangkapnya tanpa mengambil tindakan apa pun, kode yang Anda poskan akan berfungsi.

Jika Anda bermaksud ingin mengambil tindakan terhadap pengecualian tanpa menghentikan pengecualian dari menumpuk, maka Anda menginginkan sesuatu seperti ini:

try:
    do_something()
except:
    handle_exception()
    raise  #re-raise the exact same exception that was thrown
Jason Baker
sumber
88

Pertama saya kutip jawaban Jack o'Connor dari utas ini . Utas yang dirujuk ditutup jadi saya menulis di sini:

"Ada cara baru untuk melakukan ini dengan Python 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

Inilah komit yang menambahkannya: http://hg.python.org/cpython/rev/406b47c64480

Dan inilah pengarangnya, Raymond Hettinger, yang membicarakan hal ini dan semua jenis kepanasan Python lainnya: https://youtu.be/OSGv2VnC0go?t=43m23s

Tambahan saya untuk ini adalah yang setara dengan Python 2.7:

from contextlib import contextmanager

@contextmanager
def ignored(*exceptions):
    try:
        yield
    except exceptions:
        pass

Maka Anda menggunakannya seperti di Python 3.4:

with ignored(Exception):
    # your code
Jabba
sumber
55

Untuk kelengkapan:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")

Perhatikan juga bahwa Anda dapat menangkap pengecualian seperti ini:

>>> try:
...     this_fails()
... except ZeroDivisionError as err:
...     print("Handling run-time error:", err)

... dan pasang kembali pengecualian seperti ini:

>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('An exception flew by!')
...     raise

... contoh dari tutorial python .

cbare
sumber
43

Bagaimana cara mengabaikan Pengecualian?

Ada beberapa cara untuk melakukan ini.

Namun, pilihan contoh memiliki solusi sederhana yang tidak mencakup kasus umum.

Khusus untuk contoh:

Dari pada

try:
    shutil.rmtree(path)
except:
    pass

Melakukan hal ini:

shutil.rmtree(path, ignore_errors=True)

Ini adalah argumen khusus untuk shutil.rmtree. Anda dapat melihat bantuan tentang itu dengan melakukan hal berikut, dan Anda akan melihatnya juga memungkinkan untuk fungsionalitas pada kesalahan juga.

>>> import shutil
>>> help(shutil.rmtree)

Karena ini hanya mencakup contoh kasus yang sempit, saya akan menunjukkan lebih lanjut bagaimana menangani ini jika argumen kata kunci tersebut tidak ada.

Pendekatan umum

Karena contoh di atas hanya mencakup kasus sempit pada contoh, saya akan menunjukkan lebih lanjut bagaimana menangani hal ini jika argumen kata kunci tersebut tidak ada.

Baru dalam Python 3.4:

Anda dapat mengimpor suppressmanajer konteks:

from contextlib import suppress

Tetapi hanya menekan pengecualian yang paling spesifik:

with suppress(FileNotFoundError):
    shutil.rmtree(path)

Anda akan mengabaikan FileNotFoundError:

>>> with suppress(FileNotFoundError):
...     shutil.rmtree('bajkjbkdlsjfljsf')
... 
>>> 

Dari dokumen :

Seperti halnya mekanisme lain yang benar-benar menekan pengecualian, manajer konteks ini harus digunakan hanya untuk menutupi kesalahan yang sangat spesifik di mana diam-diam melanjutkan pelaksanaan program diketahui sebagai hal yang benar untuk dilakukan.

Perhatikan itu suppressdan FileNotFoundErrorhanya tersedia dalam Python 3.

Jika Anda ingin kode Anda berfungsi di Python 2 juga, lihat bagian selanjutnya:

Python 2 & 3:

Ketika Anda hanya ingin mencoba / kecuali tanpa menangani pengecualian, bagaimana Anda melakukannya dengan Python?

Apakah mengikuti cara yang benar untuk melakukannya?

try :
    shutil.rmtree ( path )
except :
    pass

Untuk kode yang kompatibel dengan Python 2, passadalah cara yang benar untuk memiliki pernyataan yang bukan pilihan. Tetapi ketika Anda melakukan telanjang except:, itu sama seperti melakukan except BaseException:yang meliputi GeneratorExit, KeyboardInterrupt, dan SystemExit, dan secara umum, Anda tidak ingin menangkap hal-hal.

Bahkan, Anda harus spesifik dalam menyebutkan pengecualian yang Anda bisa.

Inilah bagian dari hierarki pengecualian Python (2) , dan seperti yang Anda lihat, jika Anda menangkap Pengecualian yang lebih umum, Anda dapat menyembunyikan masalah yang tidak Anda harapkan:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
... and so on

Anda mungkin ingin menangkap OSError di sini, dan mungkin pengecualian yang tidak Anda pedulikan adalah jika tidak ada direktori.

Kita bisa mendapatkan bahwa nomor kesalahan tertentu dari errnoperpustakaan, dan reraise jika kita tidak memiliki itu:

import errno

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno == errno.ENOENT: # no such file or directory
        pass
    else: # we had an OSError we didn't expect, so reraise it
        raise 

Catatan, kenaikan gaji memunculkan pengecualian asli, yang mungkin merupakan apa yang Anda inginkan dalam kasus ini. Ditulis lebih ringkas, karena kita tidak benar-benar perlu secara eksplisit passdengan kode dalam penanganan perkecualian:

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno != errno.ENOENT: # no such file or directory
        raise 
Aaron Hall
sumber
11

Ketika Anda hanya ingin melakukan tangkapan mencoba tanpa menangani pengecualian, bagaimana Anda melakukannya dengan Python?

Ini akan membantu Anda untuk mencetak apa pengecualian :( yaitu mencoba menangkap tanpa menangani pengecualian dan mencetak pengecualian.)

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]
Irengbam Tilokchan Singh
sumber
10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

FYI klausa lain bisa berlaku setelah semua pengecualian dan hanya akan dijalankan jika kode dalam percobaan tidak menyebabkan pengecualian.

MrChrisRodriguez
sumber
1
Akhirnya penjelasan yang baik elsedalam konteks ini. Dan untuk menambahkan itu finallyakan selalu berjalan setelah (atau tidak terkecuali).
not2qubit
5

Saya perlu mengabaikan kesalahan dalam beberapa perintah dan fuckit melakukan trik

import fuckit

@fuckit
def helper():
    print('before')
    1/0
    print('after1')
    1/0
    print('after2')

helper()
citynorman
sumber
+1 karena Anda pasti membuat hari saya karena di dalam kode sumber ini Anda dapat mempelajari beberapa hal yang sangat berguna seperti memodifikasi tumpukan langsung
WBAR
3

Dalam Python, kami menangani pengecualian yang mirip dengan bahasa lain, tetapi perbedaannya adalah beberapa perbedaan sintaksis, misalnya,

try:
    #Your code in which exception can occur
except <here we can put in a particular exception name>:
    # We can call that exception here also, like ZeroDivisionError()
    # now your code
# We can put in a finally block also
finally:
    # Your code...
Deepak Kumar 'SORTED'
sumber
-4

Saya biasanya hanya melakukan:

try:
    doSomething()
except:
    _ = ""
Dylan Strudwick
sumber
3
Saya akan menyarankan bahwa Anda mengganti _ = ""dengan pass.
Legorooj