เหตุใดการใช้ `หรือ 'ภายในข้อยกเว้นไม่ทำให้เกิด SyntaxError มีการใช้งานที่ถูกต้องหรือไม่


11

ที่ทำงานฉันพบexceptข้อหนึ่งกับorผู้ควบคุมเครื่อง:

try:
    # Do something.
except IndexError or KeyError:
    # ErrorHandling

ฉันรู้ว่าการเรียนการยกเว้นควรจะผ่านการเป็น tuple SyntaxErrorแต่มันเรียกร้องให้ผมว่ามันจะไม่ได้ก่อให้เกิด

ดังนั้นก่อนอื่นฉันต้องการตรวจสอบว่าใช้งานได้จริงหรือไม่ และมันก็ไม่ได้

>>> def with_or_raise(exc):
...     try:
...         raise exc()
...     except IndexError or KeyError:
...         print('Got ya!')
...

>>> with_or_raise(IndexError)
Got ya!

>>> with_or_raise(KeyError)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in with_or_raise
KeyError

ดังนั้นมันจึงไม่ได้รับการยกเว้นที่สองและเมื่อมองจาก bytecode มันชัดเจนว่าทำไม:

>>> import dis
>>> dis.dis(with_or_raise)
  2           0 SETUP_EXCEPT            10 (to 12)

  3           2 LOAD_FAST                0 (exc)
              4 CALL_FUNCTION            0
              6 RAISE_VARARGS            1
              8 POP_BLOCK
             10 JUMP_FORWARD            32 (to 44)

  4     >>   12 DUP_TOP
             14 LOAD_GLOBAL              0 (IndexError)
             16 JUMP_IF_TRUE_OR_POP     20
             18 LOAD_GLOBAL              1 (KeyError)
        >>   20 COMPARE_OP              10 (exception match)
             22 POP_JUMP_IF_FALSE       42
             24 POP_TOP
             26 POP_TOP
             28 POP_TOP

  5          30 LOAD_GLOBAL              2 (print)
             32 LOAD_CONST               1 ('Got ya!')
             34 CALL_FUNCTION            1
             36 POP_TOP
             38 POP_EXCEPT
             40 JUMP_FORWARD             2 (to 44)
        >>   42 END_FINALLY
        >>   44 LOAD_CONST               0 (None)
             46 RETURN_VALUE

ดังนั้นเราจะเห็นได้ว่าคำสั่ง 14 โหลดIndexErrorคลาสลงบนสแต็ก จากนั้นก็จะตรวจสอบว่าค่าที่Trueซึ่งมันเป็นเพราะงูหลาม truthiness และในที่สุดก็กระโดดโดยตรงกับการเรียนการสอน 20 ที่exception matchจะทำ ตั้งแต่คำสั่ง 18 ถูกข้ามไปKeyErrorไม่เคยถูกโหลดลงบนสแต็กดังนั้นจึงไม่ตรงกัน

ฉันลองด้วย Python 2.7 และ 3.6 ผลลัพธ์เดียวกัน

แต่ทำไมมันถึงเป็นไวยากรณ์ที่ถูกต้อง? ฉันคิดว่ามันเป็นหนึ่งในสิ่งต่อไปนี้:

  1. มันเป็นสิ่งประดิษฐ์จาก Python เวอร์ชั่นเก่าจริงๆ
  2. มีกรณีการใช้งานที่ถูกต้องสำหรับการใช้งานจริง orภายในexceptข้อ
  3. มันเป็นข้อ จำกัด ของ Parser Python ซึ่งอาจต้องยอมรับการแสดงออกใด ๆ หลังจาก exceptคำหลัก

การลงคะแนนของฉันคือวันที่ 3 (เนื่องจากฉันเห็นการสนทนาเกี่ยวกับ parser ใหม่สำหรับ Python) แต่ฉันหวังว่าจะมีใครบางคนสามารถยืนยันสมมติฐานนั้นได้ เพราะถ้ามันเป็น 2 ฉันต้องการรู้ว่ากรณีการใช้งาน!

นอกจากนี้ฉันยังไม่ค่อยเข้าใจวิธีการสำรวจต่อไป ฉันคิดว่าฉันจะต้องขุดลงในซอร์สโค้ดของโปรแกรมแยกวิเคราะห์ของ CPython แต่ idk จะหาได้ที่ไหนและอาจจะมีวิธีที่ง่ายกว่านี้ไหม

คำตอบ:


7

ในexcept e, eสามารถใด ๆ แสดงออกงูหลามที่ถูกต้อง:

try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ...

[..] สำหรับ exceptคำสั่งย่อยที่มีนิพจน์นิพจน์นั้นจะถูกประเมินและส่วนคำสั่งนั้นตรงกับข้อยกเว้นหากวัตถุผลลัพธ์นั้น "เข้ากันได้" พร้อมกับข้อยกเว้น วัตถุที่เข้ากันได้กับข้อยกเว้นถ้ามันเป็นชั้นหรือชั้นฐานของวัตถุข้อยกเว้นหรือสิ่งอันดับที่มีรายการที่เข้ากันได้กับข้อยกเว้น

https://docs.python.org/3/reference/compound_stmts.html#the-try-statement

การแสดงออกที่อัตราผลตอบแทนที่คุ้มค่าIndexError or KeyError IndexErrorดังนั้นนี่เท่ากับ:

except IndexError:
   ...

ขอบคุณสำหรับแสงตอบที่รวดเร็ว! เราจะพิจารณาว่าเป็นข้อ จำกัด ของ parser หรือไม่ (เช่นสามารถยอมรับการแสดงออกใด ๆ มากกว่าที่จะเจาะจงได้) หรือทางเลือกโดยเจตนาเพื่อไม่ให้ จำกัด สิ่งต่าง ๆ มากเกินไป?
Loïc Teixeira

1
ดูเหมือนว่าฉันจะยึดติดกับหลักการพื้นฐานของงูหลามที่เรียบง่ายกว่า เหตุใดจึงต้องสร้างกฎใหม่ซึ่งสามารถ จำกัด ได้เฉพาะเมื่อยอมรับการแสดงออกใด ๆ จึงหมายถึงอิสรภาพที่สมบูรณ์โดยไม่มีกรณีพิเศษใหม่
หลอกลวง

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

ฉันเดาว่าเหตุผลในการ จำกัด โอกาสที่จะป้องกันนักพัฒนาจากการเขียนรหัสซึ่งไม่ได้ทำในสิ่งที่พวกเขาตั้งใจจะทำ except IndexError or KeyErrorท้ายที่สุดการเขียนดูเหมือนจะเป็นสิ่งที่ดีในการเขียน อย่างไรก็ตามฉันเห็นด้วยกับคุณว่ามันจะขัดกับค่าอื่น ๆ ที่หลามพยายามที่จะเคารพ
Loïc Teixeira

โปรดทราบว่าไพ ธ อนยังอนุญาตให้var == 1 or 2ซึ่งในสายตาที่ไม่ได้รับการฝึกฝนยัง "ดูเหมือนว่าเป็นสิ่งที่ดีในการเขียน"
Eric

-2

คุณควรใช้ n-tuple ชนิดแทนนิพจน์โลจิคัล (ซึ่งเพิ่งส่งคืนองค์ประกอบที่ไม่ใช่เท็จแรก):

def with_or_raise(exc):
  try:
    raise exc()
  except (IndexError,KeyError):
    print('Got ya!')

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