วิธีรับข้อความยกเว้นใน Python อย่างถูกต้อง


97

วิธีใดเป็นวิธีที่ดีที่สุดในการรับข้อความยกเว้นจากส่วนประกอบของไลบรารีมาตรฐานใน Python

ฉันสังเกตเห็นว่าในบางกรณีคุณสามารถรับได้จากmessageฟิลด์เช่นนี้:

try:
  pass
except Exception as ex:
  print(ex.message)

แต่ในบางกรณี (ตัวอย่างเช่นในกรณีของข้อผิดพลาดของซ็อกเก็ต) คุณต้องทำสิ่งนี้:

try:
  pass
except socket.error as ex:
  print(ex)

ฉันสงสัยว่ามีวิธีมาตรฐานใดบ้างที่จะครอบคลุมสถานการณ์เหล่านี้ส่วนใหญ่


1
คุณกำลังรวมสองสิ่งที่แตกต่างกัน - except Foo as bar:เหมือนกับexcept Foo, bar:(ยกเว้นสิ่งที่ใหม่กว่าและจะยังคงทำงานใน 3.x) ไม่ว่าข้อผิดพลาดจะมาพร้อมกับmessageแอตทริบิวต์หรือไม่ก็ตาม
jonrsharpe

1
@FrozenHeart คุณกำลังถามว่าการเข้าถึง.messageข้อผิดพลาดเป็นวิธีมาตรฐานหรือไม่?
Anand S Kumar

ตัวอย่างที่สองของคุณprint(msg)เป็นเพียงทางลัดสำหรับprint(str(msg))
Salo

@ Anand S Kumar ใช่ จะได้ผลในทุกกรณีหรือไม่?
FrozenHeart

4
ฉันเชื่อว่าการเข้าถึงmessageถูกเลิกใช้แล้ว
Jonathon Reinhart

คำตอบ:


94

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

ยวดEnvironmentError(กับ subclasses IOErrorและOSError) มีอาร์กิวเมนต์แรกของสองของerrno strerrorไม่มีmessage... strerrorมีความคล้ายคลึงกับสิ่งที่ปกติจะเป็นmessage .

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

ฉันคิดว่าวิธีที่เหมาะสมในการจัดการสิ่งนี้คือการระบุExceptionคลาสย่อยเฉพาะที่คุณต้องการจับจากนั้นจับเฉพาะคลาสเหล่านั้นแทนที่จะเป็นทุกอย่างด้วย an except Exceptionจากนั้นใช้แอตทริบิวต์ใด ๆ ที่คลาสย่อยเฉพาะกำหนดตามที่คุณต้องการ

ถ้าคุณต้องมีprintบางอย่างฉันคิดว่าการพิมพ์ที่จับได้Exceptionนั้นมักจะทำในสิ่งที่คุณต้องการไม่ว่าจะมีmessageคุณลักษณะหรือไม่

นอกจากนี้คุณยังสามารถตรวจสอบแอตทริบิวต์ข้อความได้หากต้องการเช่นนี้ แต่ฉันจะไม่แนะนำจริงๆเพราะมันดูยุ่ง:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

ขอบคุณสำหรับคำตอบ. มีเหตุผลพิเศษใดบ้างที่จะใช้str(ex)แทน just ex?
FrozenHeart

3
@FrozenHeart - print()โทรstr()หาคุณโดยอัตโนมัติ ไม่มีเหตุผลที่จะเรียกตัวเองด้วยตนเองแม้ว่าจะไม่เป็นอันตรายเนื่องจากการเรียกstr()สตริงจะส่งคืนสตริง
ArtOfWarfare

1
@ArtOfWarfare ผมคิดว่าอาจจะมีปัญหาเกี่ยวกับว่าข้อความเป็นประเภทstr() unicode
kratenko

34

เพื่อปรับปรุงคำตอบโดย@artofwarfareนี่คือสิ่งที่ฉันพิจารณาวิธีที่ดีกว่าในการตรวจสอบmessageแอตทริบิวต์และพิมพ์หรือพิมพ์Exceptionวัตถุเป็นทางเลือก

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

การโทรหาreprเป็นทางเลือก แต่ฉันพบว่าจำเป็นในบางกรณีการใช้งาน


อัปเดต # 1:

ตามความคิดเห็นของ@MadPhysicistต่อไปนี้เป็นข้อพิสูจน์ว่าเหตุใดจึงreprจำเป็นต้องมีการเรียกร้อง ลองรันโค้ดต่อไปนี้ในล่ามของคุณ:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

อัปเดต # 2:

นี่คือการสาธิตเฉพาะสำหรับ Python 2.7 และ 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


1
getattrแสดงข้อยกเว้นหากวัตถุที่ส่งผ่านไม่มีแอตทริบิวต์ที่ร้องขอ ถ้าคุณอยากจะทำอะไรเช่นนั้นผมคิดว่าคุณควรใช้อาร์กิวเมนต์ที่สามที่จำเป็นสำหรับการเช่นนี้getattr print getattr(e, 'message', e)ดีกว่าสิ่งที่ฉันทำ อีกทางเลือกหนึ่งprint(e.message if hasattr(e, 'message') else e)คือ
ArtOfWarfare

2
เกือบจะแน่นอนคุณต้องการแทนstr repr
Mad Physicist

2
เมื่อเทียบกับstr, reprเพียงแค่เพิ่มชื่อชั้น แทนการใช้ผมเสนอให้ใช้repr print('{e.__class__.__name__}: {e}'.format(e=e))ผลงานพิมพ์สะอาดกว่าและเป็นไปตามผลลัพธ์ของการเพิ่มขึ้นเอง
kadee

1
ตามข้างต้นผมพบว่ามีประโยชน์มากที่สุดสำหรับผมที่จะ'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
Shadi

1
ขอบคุณ !! repr(e)ตอนนี้เป็นทางออกเดียวที่ช่วยให้ฉันพิมพ์ข้อมูลอย่างน้อยที่สุดเกี่ยวกับข้อผิดพลาดที่ฉันตรวจพบในบางสถานการณ์ repr(e)ให้ผลตอบแทนKeyError(0,)(ซึ่งเป็นข้อผิดพลาด) ในขณะที่str(e)หรือe.messageให้ผลเพียงอย่างเดียว0หรือไม่มีเลยตามลำดับ
FlorianH

0

ผมมีปัญหาเหมือนกัน. ฉันคิดว่าทางออกที่ดีที่สุดคือใช้ log.exception ซึ่งจะพิมพ์การติดตามสแต็กและข้อความแสดงข้อผิดพลาดโดยอัตโนมัติเช่น:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

1
คืออะไรlog? ฉันเพิ่งลองใช้import logPython 2.7.13 และได้รับข้อความว่าไม่มีโมดูลที่มีชื่อนั้น เป็นสิ่งที่คุณเพิ่มผ่านpipหรือถูกเพิ่มใน python เวอร์ชันใหม่กว่า (ฉันรู้ฉันรู้ฉันต้องอัปเดตเป็น Python 3 ... ฉันจะทำทันทีที่ CentOS หยุดส่งด้วย Python 2 ตามค่าเริ่มต้น ... )
ArtOfWarfare

6
เขา / เธออาจใช้โมดูลการบันทึกจาก python จากนั้นสร้างอินสแตนซ์ตัวบันทึกเป็นตัวแปรบันทึก import logging\ nlog = logging.getLogger(__name__)
Josepas

0

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

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.