일반적인 합의는 "예외를 사용하지 마십시오!" 대부분 다른 언어에서 왔으며 때로는 구식입니다.
C ++에서 던지는 예외 매우 비용이 많이 드는 "스택 해제"로 인해이. 모든 로컬 변수 선언은 with
Python 의 명령문 과 유사하며 해당 변수의 객체가 소멸자를 실행할 수 있습니다. 이 소멸자는 예외가 발생했을 때뿐만 아니라 함수에서 돌아올 때 실행됩니다. 이 "RAII 관용구"는 필수 언어 기능이며 강력하고 올바른 코드를 작성하는 것이 매우 중요합니다. 따라서 저렴한 예외를 제외하고 RAII는 C ++이 RAII에 대해 결정한 상충 관계였습니다.
초기 C ++에서는 많은 코드가 예외 안전 방식으로 작성되지 않았습니다. 실제로 RAII를 사용하지 않으면 메모리 및 기타 리소스가 유출되기 쉽습니다. 따라서 예외를 던지면 해당 코드가 잘못됩니다. C ++ 표준 라이브러리에서도 예외를 사용하기 때문에 더 이상 합리적이지 않습니다. 예외가 존재하지 않는 척할 수는 없습니다. 그러나 C 코드와 C ++를 결합 할 때 여전히 예외가 발생합니다.
Java에서 모든 예외에는 연관된 스택 추적이 있습니다. 스택 추적은 오류를 디버깅 할 때 매우 유용하지만 예외가 인쇄되지 않으면 제어 흐름에만 사용되므로 예외가 발생하지 않습니다.
따라서 이러한 언어에서는 예외가 너무 비싸서 제어 흐름으로 사용되지 않습니다. 파이썬에서는 이것이 문제가되지 않으며 예외가 훨씬 저렴합니다. 또한, 파이썬 언어는 이미 다른 제어 흐름 구조에 비해 눈에 띄지 않는 예외의 비용을하게 오버 헤드 앓고 : 예 검사를 사전인가 항목이 명시 적 회원 테스트로 존재하는 경우 if key in the_dict: ...
입니다 일반적으로 정확하게 빨리 단순히 항목에 접근 the_dict[key]; ...
하고 있는지 확인 KeyError를 얻습니다. 일부 필수 언어 기능 (예 : 생성기)은 예외 측면에서 설계되었습니다.
따라서 파이썬에서 예외를 피할 기술적 인 이유는 없지만 반환 값 대신 예외를 사용해야하는지에 대한 의문이 여전히 있습니다. 예외가있는 설계 수준 문제는 다음과 같습니다.
그들은 전혀 분명하지 않습니다. 함수를 쉽게보고 어떤 예외가 발생할 수 있는지 확인할 수 없으므로 항상 무엇을 포착해야하는지 알 수 없습니다. 반환 값은보다 명확한 경향이 있습니다.
예외는 코드를 복잡하게 만드는 비 로컬 제어 흐름입니다. 예외가 발생하면 제어 흐름이 재개 될 위치를 알 수 없습니다. 즉시 처리 할 수없는 오류의 경우 이는 호출자에게 상태를 알리면 전적으로 불필요합니다.
파이썬 문화는 일반적으로 예외에 찬성하여 기울어 져 있지만 쉽게 넘어갈 수 있습니다. list_contains(the_list, item)
목록에 해당 항목과 동일한 항목이 포함되어 있는지 확인 하는 함수를 상상해보십시오 . 결과가 절대적으로 성가신 예외를 통해 전달되면 다음과 같이 호출해야하기 때문입니다.
try:
list_contains(invited_guests, person_at_door)
except Found:
print("Oh, hello {}!".format(person_at_door))
except NotFound:
print("Who are you?")
부울을 반환하는 것이 훨씬 명확합니다.
if list_contains(invited_guests, person_at_door):
print("Oh, hello {}!".format(person_at_door))
else:
print("Who are you?")
함수가 이미 값을 반환한다고 가정하면 사람들 이이 값을 확인하는 것을 잊어 버릴 수 있기 때문에 특수 조건에 대한 특수 값을 반환하는 것은 다소 오류가 발생하기 쉽습니다 (C의 1/3 문제의 원인 일 수 있음). 일반적으로 예외가 더 정확합니다.
좋은 예는 `haystack 문자열에서 문자열 pos = find_string(haystack, needle)
의 첫 항목을 검색 needle
하고 시작 위치를 반환하는 함수입니다. 그러나 그들이 건초 줄에 바늘 줄이 없다면 어떻게 될까요?
C에 의한 솔루션과 파이썬에 의해 흉내 낸 솔루션은 특별한 값을 반환하는 것입니다. C에서 이것은 널 포인터이고, 파이썬에서 이것은입니다 -1
. 이것은 특히 -1
파이썬에서 유효한 인덱스 처럼 위치를 검사하지 않고 문자열 인덱스로 사용할 때 놀라운 결과를 초래할 것 입니다. C에서 NULL 포인터는 적어도 segfault를 제공합니다.
PHP에서는 다른 유형의 특수 값인 FALSE
정수 대신 부울이 반환 됩니다. 결과적으로 언어의 암시 적 변환 규칙으로 인해 실제로 더 나아지는 것은 아닙니다 (그러나 파이썬에서는 부울을 정수로 사용할 수 있습니다!). 일관된 유형을 반환하지 않는 함수는 일반적으로 매우 혼란스러운 것으로 간주됩니다.
보다 강력한 변형은 문자열을 찾을 수 없을 때 예외를 throw하는 것이 었으므로 정상적인 제어 흐름 중에 실수로 일반 값 대신 특수 값을 사용할 수 없습니다.
try:
pos = find_string(haystack, needle)
do_something_with(pos)
except NotFound:
...
또는 항상 직접 사용할 수 없지만 먼저 래핑 해제해야하는 유형을 반환 할 수 있습니다 (예 : 부울이 예외 발생 여부 또는 결과 사용 가능 여부를 나타내는 결과 부울 튜플). 그때:
pos, ok = find_string(haystack, needle)
if not ok:
...
do_something_with(pos)
이렇게하면 문제를 즉시 처리 할 수 있지만 매우 성가시다. 또한 체인 기능을 쉽게 할 수 없습니다. 모든 함수 호출에는 이제 세 줄의 코드가 필요합니다. 골랑은이 귀찮은 것이 가치가 있다고 생각하는 언어입니다.
요약하자면, 예외는 문제가없는 것은 아니며, 특히 "정상"반환 값을 대체 할 때 확실히 과용 될 수 있습니다. 그러나 오류가 아닌 특수 조건을 신호하는 데 사용되는 예외를 사용하면 깨끗하고 직관적이며 사용하기 쉽고 오용하기 어려운 API를 개발할 수 있습니다.