except 절에서`or`를 사용하면 왜 SyntaxError가 발생하지 않습니까? 올바른 사용법이 있습니까?


11

직장에서 나는 연산자 except와 절을 우연히 발견했습니다 or.

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

예외 클래스가 튜플로 전달되어야한다는 것을 알고 있지만 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

따라서 두 번째 예외를 포착하지 않았고 바이트 코드를 살펴보면 이유가 더 분명해집니다.

>>> 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, 파이썬 진실성 때문 인지 확인 하고 마지막으로 명령 20으로 바로 이동 exception match합니다. 명령 18을 건너 뛰었 KeyError으므로 스택에로드되지 않았으므로 일치하지 않습니다.

Python 2.7 및 3.6으로 동일한 결과를 시도했습니다.

그렇다면 왜 유효한 구문입니까? 나는 그것이 다음 중 하나라고 상상합니다.

  1. 정말 오래된 버전의 파이썬에서 나온 인공물입니다.
  2. 실제로 or는 except조항 내에서 사용하기위한 유효한 사용 사례 가 있습니다.
  3. except키워드 뒤에 식을 허용해야 할 수도있는 Python 파서의 제한 사항입니다 .

내 투표는 3에 있습니다 (파이썬의 새로운 파서에 대한 토론을 보았지만) 누군가 그 가설을 확인할 수 있기를 바랍니다. 예를 들어 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:
   ...

그 조명 빠른 답변에 감사드립니다! 파서를 제한하는 것 (즉, 좀 더 구체적인 표현을 받아 들일 수없는 것)이나 너무 많은 것을 제한하지 않기 위해 신중한 선택으로 간주 할 수 있습니까?
— Loïc Teixeira

1
더 간단한 기본 파이썬 원칙을 고수하는 것 같습니다. 어떤 표현을 받아 들일 때 새로운 특별한 경우없이 완전한 자유를 의미 할 때 제한 할 수있는 새로운 규칙을 발명하는 이유는 무엇입니까?
— deceze

의도적으로 선택하여 예외의 튜플을 동적으로 잡아서 except명령문 에 그러한 값을 사용하도록 할 수 있습니다.
— user4815162342

가능성을 제한하는 이유는 개발자가 의도 한 것을 수행하지 않는 코드를 작성하지 못하게하는 것입니다. 결국, 글을 쓰는 except IndexError or KeyError것은 괜찮은 것 같습니다. 그러나 나는 파이썬이 존중하려고하는 다른 가치에 위배된다는 것에 동의합니다.
— Loïc Teixeira

파이썬은 또한 var == 1 or 2훈련되지 않은 눈에 "쓰기가 괜찮은 것 같습니다"라고 허용합니다.
— Eric

-2

논리적 표현식 대신 첫 번째 유형의 거짓 요소를 반환하는 대신 n- 튜플 유형을 사용해야합니다.

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

질문에서 언급했듯이 예외 클래스가 튜플로 전달되어야한다는 것을 알고 있지만 사용 or이 여전히 유효한 Python 인지 궁금 합니다.
— Loïc Teixeira
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.