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. 실제로 orexcept조항 내에서 사용하기위한 유효한 사용 사례 가 있습니다.
  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.