วิธีละเว้นข้อยกเว้นอย่างถูกต้อง


776

เมื่อคุณต้องการลองทำข้อยกเว้นโดยไม่ต้องจัดการข้อยกเว้นคุณจะทำอย่างไรใน Python

วิธีต่อไปนี้ถูกต้องหรือไม่

try:
    shutil.rmtree(path)
except:
    pass

10
แปลกที่ไม่มีใครกล่าวว่าจนถึงขณะนี้ (ที่ฉันได้ในคำตอบของฉัน) shutil.rmtree(path, ignore_errors=True)แต่สำหรับฟังก์ชั่นนี้เฉพาะคุณก็สามารถทำ อย่างไรก็ตามวิธีนี้ใช้ไม่ได้กับฟังก์ชั่นส่วนใหญ่
Aaron Hall

9
การอ่านสำคัญเมื่อคิดถึงการละเว้นข้อยกเว้น: ทำไม“ ยกเว้น: ผ่าน” การฝึกเขียนโปรแกรมที่ไม่ดี
กระตุ้น

3
ลองนึกภาพการทำสิ่งนี้ในชีวิตจริง ลอง: get_cash ( '$ 1000) ยกเว้นผ่าน # Meh ก็อาจจะถูกปรับ
Grokodile

คำตอบ:


1039
try:
    doSomething()
except: 
    pass

หรือ

try:
    doSomething()
except Exception: 
    pass

ความแตกต่างคือว่าครั้งแรกที่หนึ่งจะจับKeyboardInterrupt, SystemExitและสิ่งที่ชอบที่จะได้มาโดยตรงจากไม่exceptions.BaseExceptionexceptions.Exception

ดูเอกสารประกอบสำหรับรายละเอียด:


4
โปรดทราบว่า StopIteration และ Warning ทั้งสองสืบทอดมาจากข้อยกเว้นเช่นกัน คุณอาจต้องการรับมรดกจาก StandardError แทนทั้งนี้ขึ้นอยู่กับความต้องการของคุณ
Ben Blank

1
นี่เป็นเรื่องจริง แต่ถ้าคุณไม่ระวังคุณสามารถพบข้อบกพร่องเล็กน้อย (โดยเฉพาะอย่างยิ่งถ้าคุณกำลังทำสิ่งอื่นที่ไม่ใช่ส่งผ่าน StopIteration)
เจสันเบเกอร์

17
-1 try: shuti.rmtree(...) except: passจะระงับข้อผิดพลาดใด ๆ อย่างไม่หยุดยั้ง (แม้ว่าคุณจะสะกดผิดshutilทำให้ a NameError) - อย่างน้อยที่สุดก็ทำได้except OSError:
dbr

44
คำตอบนี้ในขณะที่มีข้อมูลขาดข้อมูลสำคัญ - คุณไม่ควรพลาดด้วยวิธีนี้ คุณควรพยายามที่จะจับข้อยกเว้นที่คุณสนใจไม่เช่นนั้นคุณจะมีฝันร้ายเมื่อต้องตามล่าข้อบกพร่องเล็ก ๆ น้อย ๆ ที่ซ่อนอยู่โดยทั่วไปของคุณ "ยกเว้น" ดูคำตอบของ dbr สำหรับข้อมูลเพิ่มเติม (ฉันรู้ว่านี่ไม่ใช่คำถามเดิม - แต่ใครกำลังมองหาเพียงแค่นี้จะนำตัวอย่างของคุณและใช้งานได้ตามที่เป็นอยู่)
johndodo

139

โดยทั่วไปถือว่าเป็นแนวปฏิบัติที่ดีที่สุดในการตรวจจับข้อผิดพลาดที่คุณสนใจในกรณีที่shutil.rmtreeเป็นไปได้OSError:

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

หากคุณต้องการเพิกเฉยต่อข้อผิดพลาดนั้นคุณจะทำ:

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

ทำไม? สมมติว่าคุณผ่านฟังก์ชันจำนวนเต็มแทนสตริงโดยไม่ตั้งใจ

shutil.rmtree(2)

มันจะให้ข้อผิดพลาด"TypeError: บังคับให้ Unicode: ต้องการสตริงหรือบัฟเฟอร์พบ int" - คุณอาจไม่ต้องการที่จะเพิกเฉยซึ่งอาจเป็นการยากที่จะแก้ปัญหา

หากคุณแน่นอนต้องการที่จะไม่สนใจข้อผิดพลาดทั้งหมดจับExceptionมากกว่าเปลือยexcept:คำสั่ง อีกครั้งทำไม

การไม่ระบุข้อยกเว้นจะดึงดูดทุกข้อยกเว้นรวมถึงSystemExitข้อยกเว้นที่ตัวอย่างเช่นsys.exit()ใช้:

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

เปรียบเทียบสิ่งต่อไปนี้ซึ่งออกอย่างถูกต้อง:

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

หากคุณต้องการเขียนโค้ดให้ทำงานได้ดีขึ้นOSErrorข้อยกเว้นสามารถแสดงถึงข้อผิดพลาดต่าง ๆ ได้ แต่ในตัวอย่างข้างต้นเราเพียง แต่ต้องการละเว้นErrno 2ดังนั้นเราจึงอาจมีความเฉพาะเจาะจงมากขึ้น:

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

1
shutil.rmtreeไม่ได้เป็นตัวอย่างที่ดีที่สุดเพราะคุณก็จะใช้ignore_errors=Trueสำหรับการทำงานว่า ..
Wim

113

เมื่อคุณเพียงแค่ต้องการลองจับโดยไม่ต้องจัดการข้อยกเว้นคุณจะทำอย่างไรใน Python?

ขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "จัดการ"

หากคุณต้องการจับโดยไม่ต้องดำเนินการใด ๆ รหัสที่คุณโพสต์จะใช้งานได้

หากคุณหมายความว่าคุณต้องการดำเนินการกับข้อยกเว้นโดยไม่หยุดข้อยกเว้นจากการขึ้นสแต็กคุณก็ต้องการสิ่งนี้:

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

88

ก่อนอื่นฉันขออ้างอิงคำตอบของ Jack o'Connor จากกระทู้นี้ กระทู้ที่อ้างอิงได้ปิดดังนั้นฉันเขียนที่นี่:

"มีวิธีใหม่ในการทำสิ่งนี้ใน Python 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

นี่คือความมุ่งมั่นที่เพิ่มเข้ามา: http://hg.python.org/cpython/rev/406b47c64480

และนี่คือผู้เขียน Raymond Hettinger พูดถึงเรื่องนี้และทุกประเภทของ Python hotness อื่น ๆ : https://youtu.be/OSGv2VnC0go?t=43m23s

สิ่งที่เพิ่มเข้ามาของฉันคือ Python 2.7 ที่เทียบเท่า:

from contextlib import contextmanager

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

จากนั้นคุณใช้เหมือนใน Python 3.4:

with ignored(Exception):
    # your code

55

เพื่อความสมบูรณ์:

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

โปรดทราบว่าคุณสามารถดักจับข้อยกเว้นดังนี้:

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

... และยกข้อยกเว้นเช่นนี้อีกครั้ง:

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

... ตัวอย่างจากหลามกวดวิชา


43

วิธีการละเว้นข้อยกเว้นอย่างถูกต้อง?

มีหลายวิธีในการทำเช่นนี้

อย่างไรก็ตามตัวเลือกตัวอย่างมีวิธีแก้ไขปัญหาอย่างง่ายที่ไม่ครอบคลุมกรณีทั่วไป

เฉพาะตัวอย่าง:

แทน

try:
    shutil.rmtree(path)
except:
    pass

ทำเช่นนี้:

shutil.rmtree(path, ignore_errors=True)

shutil.rmtreeนี้เป็นเฉพาะอาร์กิวเมนต์ คุณสามารถดูความช่วยเหลือได้โดยทำสิ่งต่อไปนี้และคุณจะเห็นว่าสามารถช่วยให้เกิดข้อผิดพลาดได้เช่นกัน

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

เนื่องจากสิ่งนี้ครอบคลุมเฉพาะกรณีตัวอย่างแคบ ๆ ฉันจะแสดงให้เห็นถึงวิธีการจัดการสิ่งนี้หากไม่มีข้อโต้แย้งคำหลักเหล่านั้น

วิธีการทั่วไป

เนื่องจากด้านบนครอบคลุมเฉพาะกรณีตัวอย่างแคบ ๆ ฉันจะแสดงให้เห็นถึงวิธีการจัดการต่อไปหากไม่มีข้อโต้แย้งคำหลักเหล่านั้น

ใหม่ใน Python 3.4:

คุณสามารถนำเข้าตัวsuppressจัดการบริบท:

from contextlib import suppress

แต่จะระงับข้อยกเว้นเฉพาะที่สุดเท่านั้น:

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

คุณจะไม่สนใจFileNotFoundError:

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

จากเอกสาร :

เช่นเดียวกับกลไกอื่น ๆ ที่ระงับข้อยกเว้นได้อย่างสมบูรณ์ผู้จัดการบริบทนี้ควรใช้เพื่อครอบคลุมข้อผิดพลาดเฉพาะอย่างยิ่งซึ่งการดำเนินการโปรแกรมต่อไปอย่างเงียบ ๆ เป็นสิ่งที่ต้องทำ

โปรดทราบว่าsuppressและFileNotFoundErrorมีเฉพาะใน Python 3 เท่านั้น

หากคุณต้องการให้โค้ดทำงานใน Python 2 ด้วยโปรดดูหัวข้อถัดไป:

Python 2 และ 3:

เมื่อคุณต้องการลอง / ยกเว้นโดยไม่ต้องจัดการข้อยกเว้นคุณจะทำอย่างไรใน Python

วิธีต่อไปนี้ถูกต้องหรือไม่

try :
    shutil.rmtree ( path )
except :
    pass

สำหรับโค้ดที่เข้ากันได้ของ Python 2 passเป็นวิธีที่ถูกต้องในการมีคำสั่งที่ไม่ใช้งาน แต่เมื่อคุณทำเปลือยexcept:ที่เป็นเช่นเดียวกับการทำexcept BaseException:ซึ่งรวมถึงGeneratorExit, KeyboardInterruptและSystemExitและโดยทั่วไปคุณไม่ต้องการที่จะจับสิ่งเหล่านั้น

ที่จริงแล้วคุณควรเจาะจงในการตั้งชื่อข้อยกเว้นเท่าที่จะทำได้

นี่คือส่วนหนึ่งของลำดับชั้นข้อยกเว้น Python (2) และอย่างที่คุณเห็นหากคุณมีข้อยกเว้นทั่วไปมากขึ้นคุณสามารถซ่อนปัญหาที่คุณไม่คาดหวัง:

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

คุณอาจต้องการจับ OSError ที่นี่และข้อยกเว้นที่คุณไม่สนใจคือถ้าไม่มีไดเรกทอรี

เราสามารถรับหมายเลขข้อผิดพลาดเฉพาะนั้นได้จากerrnoห้องสมุดและรับอีกหากเราไม่มี:

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 

หมายเหตุการเพิ่มเปล่าจะยกข้อยกเว้นดั้งเดิมซึ่งอาจเป็นสิ่งที่คุณต้องการในกรณีนี้ เขียนให้กระชับยิ่งขึ้นเนื่องจากเราไม่จำเป็นต้องpassใช้โค้ดในการจัดการข้อยกเว้นอย่างชัดเจน:

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

11

เมื่อคุณเพียงแค่ต้องการลองจับโดยไม่ต้องจัดการข้อยกเว้นคุณจะทำอย่างไรใน Python?

วิธีนี้จะช่วยให้คุณพิมพ์ข้อยกเว้นคือ: (ลองใช้ catch โดยไม่ต้องจัดการข้อยกเว้นและพิมพ์ข้อยกเว้น)

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]

10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

FYI ส่วนคำสั่งอื่นสามารถไปหลังจากข้อยกเว้นทั้งหมดและจะทำงานเฉพาะถ้ารหัสในการลองไม่ก่อให้เกิดข้อยกเว้น


1
ในที่สุดคำอธิบายที่ดีของelseในบริบทนี้ และจะเพิ่มที่finallyจะเสมอทำงานหลังจากที่ใด ๆ (หรือไม่มีข้อยกเว้น)
not2qubit

5

ฉันต้องการละเว้นข้อผิดพลาดในหลายคำสั่งและfuckitทำเคล็ดลับ

import fuckit

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

helper()

+1 เพราะคุณทำให้วันของฉันเป็นจริงเพราะในซอร์สโค้ดนี้คุณสามารถเรียนรู้สิ่งที่มีประโยชน์อย่างยิ่งเช่นการแก้ไข live stack
WBAR

3

ใน Python เราจัดการข้อยกเว้นที่คล้ายกับภาษาอื่น ๆ แต่ความแตกต่างคือความแตกต่างของไวยากรณ์ตัวอย่างเช่น

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...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.