항상`except` 문에 예외 유형을 지정해야합니까?


93

PyCharm IDE를 사용할 때 except:예외 유형없이를 사용 하면 IDE에서이 예외 절이 Too broad.

이 조언을 무시해야합니까? 아니면 항상 예외 유형을 지정하는 것이 Pythonic입니까?


답변보다 이것에 대해 더 많이 알고 싶다면 Google은 예외를 삼키십시오. 모든 종류의 다른 흥미로운 할 일과하지 말아야 할 일을 할 수 있습니다. 코드 냄새는 또 다른 것입니다.
Tony Hopkinson 2013

답변:


89

거의 항상 명시적인 예외 유형을 지정하는 것이 좋습니다. 네이 키드 except:절 을 사용하면 잡을 것으로 예상되는 것 이외의 예외를 잡을 수 있습니다. 이것은 버그를 숨기거나 예상 한대로 수행하지 않을 때 프로그램을 디버그하기 어렵게 만들 수 있습니다.

예를 들어, 데이터베이스에 행을 삽입하는 경우 행이 이미 존재 함을 나타내는 예외를 포착하여 업데이트를 수행 할 수 있습니다.

try:
    insert(connection, data)
except:
    update(connection, data)

bare를 지정 except:하면 데이터베이스 서버가 넘어 졌음을 나타내는 소켓 오류도 포착됩니다. 처리하는 방법을 알고있는 예외 만 포착하는 것이 가장 좋습니다. 프로그램이 계속해서 예기치 않은 방식으로 작동하는 것보다 예외 시점에서 실패하는 것이 더 낫습니다.

베어를 사용하고 싶은 한 가지 경우 except:는 네트워크 서버처럼 항상 실행해야하는 프로그램의 최상위 수준에 있습니다. 하지만 예외를 기록하는 데 매우주의해야합니다. 그렇지 않으면 무엇이 잘못되었는지 알아낼 수 없습니다. 기본적으로이 작업을 수행하는 프로그램에는 최대 한 곳만 있어야합니다.

이 모든에 대한 추론 코드를하지 않을해야한다는 것입니다 raise Exception('some message')그것을 사용하는 클라이언트 코드를 강제하기 때문에 except:(또는 except Exception:어떤 거의 나쁜로). 신호를 보내려는 문제에 특정한 예외를 정의해야합니다 ( ValueError또는 같은 일부 내장 예외 하위 클래스에서 상속 될 수 있음 TypeError). 또는 특정 내장 예외를 발생시켜야합니다. 이를 통해 코드 사용자는 처리하려는 예외 만 포착 할 때주의 할 수 있습니다.


7
+1 매우 사실입니다. 예를 들어 더 재미있게 볼 수 있습니다. except:또한 catches (다른 많은 것 중에서) NameErrorAttributeError, 따라서 try블록 에서 철자를 잘못 입력하면 (예 : "insert"함수가 실제로 필요한 insert_one만큼 일관성을 중요하게 생각하지 않았기 때문에 호출 됩니다), 항상 조용히 시도합니다 update().

1
그렇다면 현재 호출 사이트 위로 예외가 발생하지 않도록해야하는 경우는 어떻습니까? 즉, 던져 질 것으로 예상 할 수있는 모든 특정 예외를 포착했습니다. 이제 "내가 생각하지 못했던이 문제가 발생하면 실행중인 실행 컨텍스트를 죽이기 전에 기록해야합니다."(예 : main())?
Adam Parkin 2015 년

이것이 바로 'One case ...'로 시작하는 문단에서 제가 말하는 상황입니다. 때로 꼭 필요하지만, 어떤 프로그램도 그렇게하는 곳이 하나만 있어야합니다. 그리고 무슨 일이 일어나고 있는지 로그에 명확하게 표시되도록주의해야합니다. 그렇지 않으면 프로그램이 이벤트 / 요청 / 무엇이든 올바르게 처리하지 않는 이유를 알아 내느라 답답한 시간을 갖게됩니다.
babbageclunk 2015 년

3
@delnan : 그보다 더 나쁩니다. except Exception:잡을 것입니다 NameErrorAttributeError도. except:나쁘게 만드는 것은 비즈니스가 걸리지 않는 물건을 잡는다는 것입니다. 예를 들어 SystemExit( exit또는 을 호출 할 때 발생 sys.exit하고 이제 의도 한 이탈을 막았습니다) 그리고 KeyboardInterrupt(다시 말하지만, 사용자가을 눌렀 Ctrl-C다면 아마도 원하지 않을 것입니다. 그들을 괴롭히기 위해 계속 달리기 위해). 후자 만이 실제로 잡을 수 있으며 명시 적으로 잡아야합니다. 적어도이 except Exception:두 가지가 정상적으로 전파되도록합니다.
ShadowRanger 2015

38

통역사가 제공하는 조언을 무시해서는 안됩니다.

로부터 PEP-8 파이썬 스타일 가이드 :

예외를 잡을 때, 제외 : 절을 사용하는 대신 가능하면 특정 예외를 언급하십시오.

예를 들어 다음을 사용하십시오.

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

bare except : 절은 SystemExit 및 KeyboardInterrupt 예외를 포착하여 Control-C로 프로그램을 중단하기 어렵게 만들고 다른 문제를 위장 할 수 있습니다. 프로그램 오류를 알리는 모든 예외를 포착하려면 except Exception :을 사용하십시오 (bare except는 BaseException :을 제외하는 것과 동일합니다).

경험상 가장 좋은 방법은 'except'절의 사용을 두 가지 경우로 제한하는 것입니다.

예외 처리기가 트레이스 백을 인쇄하거나 기록하는 경우; 최소한 사용자는 오류가 발생했음을 알게됩니다. 코드가 일부 정리 작업을 수행해야하지만 예외가 발생하여 위로 전파되도록합니다. try ... finally는이 경우를 처리하는 더 좋은 방법이 될 수 있습니다.



9

파이썬에만 국한되지 않습니다.

예외의 요점은 가능한 한 문제가 발생한 위치에 가깝게 문제를 처리하는 것입니다.

따라서 예외적 인 상황에서 문제를 유발할 수있는 코드와 해결 방법을 서로 "다음"으로 유지할 수 있습니다.

문제는 코드에서 발생할 수있는 모든 예외를 알 수 없다는 것입니다. 당신이 알 수있는 것은 만약 그것이 파일을 찾을 수 없다는 예외라면, 당신은 그것을 트랩하고 사용자에게 함수를 가져 오거나 취소하도록 프롬프트 할 수 있다는 것입니다.

try catch를 넣으면 파일 루틴 (읽기 전용, 권한, UAC, 실제로는 pdf가 아닌 등)에 어떤 문제가 있더라도 모든 파일이 catch를 찾을 수 없으며 사용자가 파일에 드롭됩니다. "하지만 거기에,이 코드는 쓰레기"라고 외치고 있습니다.

이제 모든 것을 잡을 수있는 몇 가지 상황이 있지만 의식적으로 선택해야합니다.

그들은 캐치, 일부 로컬 작업 (예 : 리소스 생성 또는 잠금 (예 : 쓰기 위해 디스크에서 파일 열기))을 실행 취소 한 다음 예외를 다시 throw하여 상위 수준에서 처리합니다.

다른 하나는 왜 그것이 잘못되었는지 상관하지 않는다는 것입니다. 예를 들어 인쇄. 프린터에 문제가 있습니다. 문제를 해결하고 응용 프로그램을 종료하지 마십시오. 코드가 일종의 일정을 사용하여 일련의 개별 작업을 실행했다면 비슷한 헛된 일이지만 작업 중 하나가 실패했기 때문에 전체가 죽기를 원할 것입니다.

참고 위의 작업을 수행하면 일종의 예외 로깅 (예 : catch log end)을 권장 할 수 없습니다.


균형에 관한 것입니다. 예외를 복구 할 수있을만큼 일찍 예외를 잡아야하고 어디로 가야할지 충분히 늦게 잡아야합니다. 이것이 Java 예외 처리가 이러한 혼란을 일으키는 이유입니다. 각 단계에서 예외를 다시 래핑해야하고 정보가 손실되기 때문입니다.
dhill

2
+1은 "왜 잘못되었는지 상관 없습니다." URL에서 날짜 / 시간을 구문 분석하는 한 줄의 코드 주위 여러 곳에서 사용하고 있습니다. 타사 날짜 / 시간 구문 분석 라이브러리는 발생할 수있는 모든 예외를 나열하지 않습니다 (표준 ValueError 외에도 OverflowError 및 TypeError를 찾았지만 아마도 더 많음), 어쨌든 이유는 신경 쓰지 않습니다 예외가 발생했습니다. 날짜 / 시간에 문제가 있다는 사용자에게 합리적인 오류 메시지를 다시 제공하고 싶습니다.
Michael Rodby

3

예를 들어 Control-C도 잡을 수 있으므로 다시 "던지기"전까지는하지 마십시오. 그러나이 경우에는 "finally"를 사용해야합니다.


3

항상 같은 당신이 캐치하지 않으려는 많은 유형이있다, 예외 유형을 지정 SyntaxError, KeyboardInterrupt, MemoryError


2
을 사용 except Exception:하면 우리가 잡고 싶지 않은 위의 유형을 피할 수 있습니까?
HorseloverFat 2013

except Exception괜찮습니다.
Ulrich Eckhardt 2013

4
@HorseloverFat : except Exception캐치 SyntaxErrorMemoryError기본 클래스이기 때문입니다. KeyboardInterrupt, SystemExit(에 의해 발생 sys.exit()) 포착되지 않음 (즉시 BaseException 하위 클래스 임)
jfs

이상적이지 않은 것처럼 들립니다. 더 정확하게 지정하는 것이 좋습니다.
HorseloverFat 2013

3

내가 사용하는 곳은 다음과 같습니다.

  1. 빠르고 더러운 프로토 타이핑

이것이 확인되지 않은 예외에 대한 내 코드의 주요 용도입니다.

  1. 잡히지 않은 모든 예외를 기록하는 최상위 main () 함수

나는 항상 이것을 추가하여 프로덕션 코드가 스택 트레이스를 유출하지 않도록합니다.

  1. 애플리케이션 레이어 간

두 가지 방법이 있습니다.

  • 첫 번째 방법 : 상위 계층이 하위 수준 함수를 호출 할 때 "상위"하위 수준 예외를 처리하기 위해 형식화 된 예외로 호출을 래핑합니다. 하지만 저수준 함수에서 처리되지 않은 저수준 예외를 감지하기 위해 일반 except 문을 추가합니다.

이 방법을 선호합니다. 어떤 예외가 적절하게 포착되어야하는지 더 쉽게 감지 할 수 있습니다. 낮은 수준의 예외가 더 높은 수준에서 기록 될 때 문제를 더 잘 볼 수 있습니다.

  • 두 번째 방법 : 하위 수준 레이어의 각 최상위 수준 함수는 해당 특정 레이어에서 처리되지 않은 모든 예외를 포착하는 것을 제외하고는 일반 코드로 래핑됩니다.

일부 동료는 이러한 방식을 선호합니다. 이는 하위 수준 기능에서 하위 수준 예외를 유지하기 때문에 "속한다".


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.