Python“ เพิ่มจาก” การใช้งาน


197

ความแตกต่างระหว่างraiseและraise fromในงูใหญ่คืออะไร?

try:
    raise ValueError
except Exception as e:
    raise IndexError

ซึ่งให้ผลผลิต

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError
IndexError

และ

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

ซึ่งให้ผลผลิต

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError from e
IndexError

9
คุณอ่านPEP-3134หรือยัง
jonrsharpe

4
ตอนนี้ใช้raise IndexError from Noneพูด
Martijn Pieters

11
หึ raise IndexError from Falseยกไม่ใช่TypeError IndexErrorทำวันของฉัน
นักฟิสิกส์บ้า


ไม่แน่ใจว่านี่เป็นสถานที่ที่เหมาะสมในการพูดถึงหรือไม่ แต่สำหรับทุกคนที่ใช้ Spyder: โครงสร้างทั้งหมดนี้ใช้ไม่ได้ เป็นปัญหามานานกว่า 3 ปีแล้ว ( github.com/spyder-ide/spyder/issues/2943 ) แต่ดูเหมือนว่าพวกเขาคิดว่าไม่จำเป็นต้องมีข้อยกเว้นที่ถูกผูกมัด
Emil Bode

คำตอบ:


230

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

การตั้งค่า__context__เกิดขึ้นถ้าคุณใช้raiseในตัวจัดการข้อยกเว้น; หากคุณใช้raiseที่อื่นก็ไม่__context__ได้ตั้งค่าไว้

หากมีการ__cause__ตั้งค่า__suppress_context__ = Trueสถานะจะถูกตั้งค่าในข้อยกเว้น; เมื่อ__suppress_context__มีการตั้งค่าTrueที่__context__จะถูกละเว้นเมื่อพิมพ์ traceback

เมื่อเพิ่มทุนจากการจัดการข้อยกเว้นที่คุณไม่ต้องการที่จะแสดงบริบท (ไม่ต้องการให้ในระหว่างการจัดการข้อยกเว้นอื่นที่เกิดขึ้นข้อความ) แล้วใช้raise ... from Noneชุดการ__suppress_context__True

กล่าวอีกนัยหนึ่ง Python ตั้งค่าบริบทเป็นข้อยกเว้นเพื่อให้คุณสามารถวิปัสสนาที่มีการยกข้อยกเว้นทำให้คุณเห็นว่ามีข้อยกเว้นอื่นถูกแทนที่ด้วยหรือไม่ คุณยังสามารถเพิ่มสาเหตุให้กับข้อยกเว้นทำให้การสืบค้นกลับชัดเจนเกี่ยวกับข้อยกเว้นอื่น ๆ (ใช้ถ้อยคำที่แตกต่างกัน) และบริบทจะถูกละเว้น (แต่ยังสามารถถูกวิปัสสนาเมื่อทำการดีบัก) การใช้raise ... from Noneช่วยให้คุณไม่ต้องพิมพ์บริบท

ดูเอกสารraiseคำสั่ง :

fromประโยคที่ใช้สำหรับการยกเว้นการผูกมัด: ถ้าให้ที่สองการแสดงออกจะต้องเป็นระดับยกเว้นอื่นหรืออินสแตนซ์ซึ่งจากนั้นจะแนบไปกับข้อยกเว้นยกเป็น__cause__แอตทริบิวต์ (ซึ่งสามารถเขียนได้) หากไม่มีการจัดการข้อยกเว้นที่ยกขึ้นข้อยกเว้นทั้งสองจะถูกพิมพ์:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

กลไกที่คล้ายกันทำงานโดยปริยายหากมีการยกข้อยกเว้นภายในตัวจัดการข้อยกเว้นหรือ finallyข้อ: ข้อยกเว้นก่อนหน้านี้จะถูกแนบมาเป็น__context__แอตทริบิวต์ของข้อยกเว้นใหม่:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

ดูเอกสารประกอบข้อยกเว้นในตัวสำหรับรายละเอียดเกี่ยวกับบริบทและทำให้ข้อมูลที่แนบมากับข้อยกเว้น


11
มีเหตุผลใดที่จะเชื่อมโยงข้อยกเว้นที่ใช้fromและ__cause__แทนนัยโดยชัดเจน__context__หรือไม่ มีกรณีใดบ้างที่จะแนบข้อยกเว้นที่แตกต่างจากที่จับโดยexcept?
darkfeline

13
@darkfeline: สมมติว่า API ฐานข้อมูลของคุณรองรับการเปิดฐานข้อมูลจากแหล่งต่าง ๆ รวมถึงเว็บและดิสก์ API ของคุณจะเสมอยกDatabaseErrorถ้าเปิดฐานข้อมูลล้มเหลว แต่หากความล้มเหลวนั้นเป็นผลมาจาก a IOErrorเพราะไฟล์ไม่สามารถเปิดได้หรือเป็นHTTPErrorเพราะ URL ล้มเหลวในการทำงานนั่นคือบริบทที่คุณต้องการรวมไว้อย่างชัดเจนดังนั้นนักพัฒนาที่ใช้ API สามารถดีบักสาเหตุที่เป็นเช่นนี้ได้ raise DatabaseError from original_exceptionในขณะที่คุณใช้
Martijn Pieters

4
@darkfeline: ถ้าว่านักพัฒนาจะถูกตัดการใช้ฐานข้อมูล API ใน API ของตัวเองและต้องการที่จะผ่านในที่IOErrorหรือHTTPErrorไปของพวกเขาผู้บริโภคแล้วพวกเขาก็จะต้องใช้raise NewException from databaseexception.__cause__ตอนนี้ใช้ข้อยกเว้นที่แตกต่างจากDatabaseExceptionที่พวกเขาเพียงแค่จับ
Martijn Pieters

2
@ dan3: ไม่ก็ไม่มี ข้อยกเว้นการผูกมัดเป็นคุณสมบัติ Python 3 อย่างแท้จริง
Martijn Pieters

5
@ laike9m: คุณหมายถึงเมื่อคุณจัดการข้อยกเว้นfooและต้องการเพิ่มข้อยกเว้นใหม่barหรือไม่? แล้วคุณสามารถใช้raise bar from fooและมีงูหลามรัฐที่เกิดโดยตรงfoo barถ้าคุณไม่ใช้from fooแล้วงูใหญ่จะยังคงพิมพ์ทั้งสอง แต่รัฐว่าในระหว่างการจัดการfoo, barถูกยกขึ้นข้อความที่แตกต่างกันมีวัตถุประสงค์เพื่อธงข้อผิดพลาดที่เป็นไปได้ในการจัดการข้อผิดพลาด
Martijn Pieters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.