จับหลายข้อยกเว้นในหนึ่งบรรทัด (ยกเว้นบล็อก)


2755

ฉันรู้ว่าฉันสามารถทำได้:

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

ฉันยังสามารถทำสิ่งนี้:

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

แต่ถ้าฉันต้องการทำสิ่งเดียวกันภายในข้อยกเว้นที่แตกต่างกันสองข้อที่ดีที่สุดที่ฉันสามารถนึกได้ในตอนนี้คือการทำสิ่งนี้:

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

มีวิธีใดบ้างที่ฉันสามารถทำสิ่งนี้ (ตั้งแต่การดำเนินการเพื่อยกเว้นทั้งสองข้อsay please):

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

ตอนนี้มันใช้งานไม่ได้จริง ๆ เพราะมันตรงกับไวยากรณ์ของ:

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

ดังนั้นความพยายามของฉันในการตรวจจับข้อยกเว้นที่แตกต่างกันสองประการนั้นไม่ได้เกิดขึ้นอย่างแน่นอน

มีวิธีทำเช่นนี้หรือไม่?


6
โปรดทราบว่าใน Python 3 ไวยากรณ์หลังไม่ถูกต้องอีกต่อไป
gerrit

คำตอบ:


3723

จากเอกสาร Python :

ข้อยกเว้นอาจตั้งชื่อข้อยกเว้นหลายคนเป็น tuple วงเล็บตัวอย่างเช่น

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

หรือสำหรับ Python 2 เท่านั้น:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

การแยกข้อยกเว้นจากตัวแปรด้วยเครื่องหมายจุลภาคจะยังคงใช้งานได้ใน Python 2.6 และ 2.7 แต่ตอนนี้เลิกใช้แล้วและไม่ทำงานใน Python 3 asตอนนี้คุณควรจะใช้


9
ฉันได้ลอง ... ด้วยและจะส่งผลให้list TypeErrorดูเหมือนว่าข้อผิดพลาดจะต้องเป็นในการtupleจับการทำงานตามที่คาดไว้
BallpointBen

4
ทำไมคุณถึงเคยใช้รายการเมื่อคุณเห็นชัดเจนว่ามีการบันทึกไว้ว่าต้องใช้สิ่งอันดับในกรณีนี้
mechanical_meat

6
มันไม่ชัดเจนว่า "tuple วงเล็บ" เป็นเพียงการสร้างประโยคหรือว่า tuple bona fide ถูกต้อง "Parenthesized" ทำให้เข้าใจผิดเพราะคุณอาจสร้างสิ่งอันดับโดยไม่มีวงเล็บที่อื่นแล้วใช้ในexceptบรรทัด มันจำเป็นต้องวงเล็บเท่านั้นหากสร้างขึ้นในexceptบรรทัด
BallpointBen

5
@JosephBani แล้วนิพจน์ตัวสร้างเป็นอย่างไร
jammertheprogrammer

12
@JosephBani ไม่เป็นความจริง แต่อย่างใด ใน2 + (x * 2), (x * 2)ไม่แน่นอนขอบเขตของ วงเล็บคือโครงสร้างการจัดกลุ่มทั่วไป ลักษณะการกำหนดของ tuple ก็คือมันมีเครื่องหมายจุลภาค - ดูเอกสาร Python : "โปรดทราบว่ามันเป็นเครื่องหมายจุลภาคที่ทำให้ tuple ไม่ใช่วงเล็บ"
Soren

314

ฉันจะจับข้อยกเว้นหลายข้อในหนึ่งบรรทัดได้อย่างไร (ยกเว้นบล็อก)

ทำเช่นนี้:

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

ต้องใช้วงเล็บเนื่องจากไวยากรณ์เก่ากว่านั้นใช้เครื่องหมายจุลภาคเพื่อกำหนดวัตถุข้อผิดพลาดให้กับชื่อ asคำหลักที่จะใช้สำหรับการที่ได้รับมอบหมาย คุณสามารถใช้ชื่อใด ๆ สำหรับวัตถุข้อผิดพลาดฉันชอบerrorเป็นการส่วนตัว

ปฏิบัติที่ดีที่สุด

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

นี่คือตัวอย่างของการใช้งานง่าย:

import sys

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

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

เอกสารนี้มีไว้ที่นี่: https://docs.python.org/tutorial/errors.html

คุณสามารถกำหนดข้อยกเว้นให้กับตัวแปร ( eเป็นเรื่องปกติ แต่คุณอาจต้องการตัวแปร verbose เพิ่มเติมถ้าคุณมีการจัดการข้อยกเว้นที่ยาวนานหรือ IDE ของคุณเน้นเฉพาะการเลือกที่ใหญ่กว่านั้นเช่นเดียวกับที่ทำ) ตัวอย่างเช่นมีแอตทริบิวต์ args นี่คือตัวอย่าง:

import sys

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

โปรดสังเกตว่าใน Python 3 errวัตถุจะไม่อยู่ในขอบเขตเมื่อexceptสรุปได้ว่าบล็อก

เลิก

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

import sys

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

หากคุณเห็นการกำหนดชื่อเครื่องหมายจุลภาคใน codebase ของคุณและคุณใช้ Python 2.5 หรือสูงกว่าให้เปลี่ยนไปใช้วิธีใหม่ในการทำเพื่อให้รหัสของคุณยังคงใช้งานร่วมกันได้เมื่อคุณอัปเกรด

suppressผู้จัดการบริบท

คำตอบที่ยอมรับคือรหัส 4 บรรทัดขั้นต่ำ:

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

try, except, passสายสามารถจัดการได้ในบรรทัดเดียวกับผู้จัดการบริบทปราบที่มีอยู่ใน Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

ดังนั้นเมื่อคุณต้องการที่จะอยู่กับข้อยกเว้นบางอย่างใช้passsuppress


2
นอกจากนี้ที่ดีของsuppressจำนวนมากอ่านได้มากกว่าเพียงแค่การทำpassบนexcept
มาเช่

50

จากเอกสาร Python -> 8.3 การจัดการข้อยกเว้น :

tryคำสั่งอาจมีมากกว่าหนึ่งข้อยกเว้นในการระบุตัวจัดการสำหรับข้อยกเว้นที่แตกต่างกัน อย่างน้อยหนึ่งตัวจัดการจะถูกดำเนินการ ตัวจัดการเท่านั้นจัดการข้อยกเว้นที่เกิดขึ้นในข้อลองที่สอดคล้องกันไม่ได้อยู่ในตัวจัดการอื่น ๆ ของคำสั่งลองเดียวกัน ข้อยกเว้นอาจตั้งชื่อข้อยกเว้นหลายประการเป็น tuple วงเล็บตัวอย่างเช่น:

except (RuntimeError, TypeError, NameError):
    pass

โปรดทราบว่าจำเป็นต้องใช้วงเล็บรอบ tuple นี้เนื่องจากยกเว้นValueError, e:เป็นไวยากรณ์ที่ใช้สำหรับสิ่งที่เขียนตามปกติexcept ValueError as e:ใน Python สมัยใหม่ (อธิบายไว้ด้านล่าง) ไวยากรณ์เก่ายังคงรองรับความเข้ากันได้ย้อนหลัง วิธีexcept RuntimeError, TypeErrorนี้ไม่เทียบเท่ากับ except (RuntimeError, TypeError):แต่except RuntimeError as TypeError:ไม่ใช่สิ่งที่คุณต้องการ


35

หากคุณใช้ข้อยกเว้นเป็นจำนวนมากบ่อยครั้งคุณสามารถกำหนดสิ่งอันดับล่วงหน้าได้ดังนั้นคุณไม่จำเป็นต้องพิมพ์ซ้ำหลาย ๆ ครั้ง

#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

หมายเหตุ:

  1. หากคุณต้องจับข้อยกเว้นอื่นนอกเหนือจากที่อยู่ใน tuple ที่กำหนดไว้ล่วงหน้าคุณจะต้องกำหนดอีกข้อยกเว้นบล็อก

  2. หากคุณไม่สามารถทนกับตัวแปรโกลบอลได้ให้กำหนดมันใน main () แล้วส่งมันไปตามที่ต้องการ ...


17

วิธีหนึ่งในการทำเช่นนี้คือ ..

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. 

และอีกวิธีหนึ่งคือการสร้างวิธีการที่ดำเนินการงานโดยexceptบล็อกและเรียกมันผ่านexceptบล็อกทั้งหมดที่คุณเขียน ..

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]

ฉันรู้ว่าคนที่สองไม่ใช่วิธีที่ดีที่สุดในการทำสิ่งนี้ แต่ฉันแค่แสดงจำนวนวิธีที่จะทำสิ่งนี้


ฉันใช้อันที่สองเพราะฉันมีข้อยกเว้นต่างกันสองข้อซึ่งแต่ละข้อต้องดำเนินการแตกต่างกัน มีบางอย่างผิดปกติหรือเปล่าที่ทำอย่างนั้น?
majikman

@majikman วิธีที่สองที่มีหลาย clauses แต่ละการเรียกฟังก์ชั่นเดียวกันไม่ดีที่สุดเมื่อคุณพยายามที่จะไม่ทำซ้ำตัวเองและทำสิ่งเดียวกันสำหรับสองข้อยกเว้น (ดูคำตอบอื่น ๆ สำหรับวิธีการทำเช่นนั้น) อย่างไรก็ตามการมีหลายส่วนexceptเป็นเรื่องปกติเมื่อคุณต้องการจัดการข้อยกเว้นต่างกัน
Eponymous
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.