스택큐힙리스트

"except: pass"가 나쁜 프로그래밍 관행인 이유는 무엇인가요? 본문

카테고리 없음

"except: pass"가 나쁜 프로그래밍 관행인 이유는 무엇인가요?

스택큐힙리스트 2023. 4. 12. 17:24
반응형

나는 종종 다른 스택 오버 플로우 질문에 대한 댓글에서 # $$ * @ ^ & @ $ &의 사용이 개선되지 않는다는 것을 본다. 이게 왜 나쁜 거지? 때로는 내가 오류에 대해 신경 쓰지 않고 코드를 계속하고 싶을 때도 있다.

try:

something

except:

pass

왜 except: pass 블록을 사용하는 것은 나쁜 것일까요? 왜 나쁜 걸까요? 에러를 발생시키고 pass 하는 것 때문인가요, 아니면 어떤 에러든 except 하는 것 때문인가요?

답변 1

당신이 올바르게 추측한 대로, 그것에는 두 가지 측면이 있습니다 : except 이후 예외 유형을 지정하지 않고 어떤 오류라도 잡는 것과 그냥 지나가는 것입니다.

내 설명은 조금 길어요 - 그러니까, tl;dr로 축약하면 다음과 같습니다:

어떤 오류도 잡지 마십시오. 항상 복구할 준비가 된 예외를 지정하고 그것 만 잡아내십시오.

이외의 블록을 통과하려하지 마십시오. 명시적으로 원하는 경우가 아니라면, 이것은 일반적으로 좋은 신호가 아닙니다.

하지만 자세히 알아보자:

어떤 오류도 잡지 마세요.

보통 try 블록을 사용하는 이유는 예외가 발생할 가능성이 있다는 것을 알기 때문입니다. 따라서 무엇이 잘못될 수 있는지와 어떤 예외가 발생할 수 있는지 대략적인 아이디어를 이미 갖고 있습니다. 이러한 경우, 예외를 catch하는 것은 복구할 수 있기 때문입니다. 즉, 예외에 대비하고 그 예외가 발생할 경우 따르게 될 대안 계획이 있습니다.

예를 들어, 사용자가 숫자를 입력하도록 요청할 때, 입력을 int() 를 사용하여 변환하면 ValueError 가 발생할 수 있습니다. 사용자에게 다시 시도해 보도록 요청함으로써 ValueError 를 쉽게 복구할 수 있으므로 해당 예외를 가져와 사용자에게 다시 프롬프트하는 것이 적절한 계획일 것입니다. 다른 예로는 파일에서 구성 정보를 읽으려고 할 때 해당 파일이 존재하지 않는 경우가 있습니다. 구성 파일이므로, 대체 구성으로 기본 구성을 가지고 있을 수 있으므로 파일이 정확히 필요하지 않을 수 있습니다. 따라서 FileNotFoundError 을 가져와 기본 구성을 적용하는 것이 여기서 좋은 계획일 것입니다. 이 두 가지 경우 모두, 예상하는 매우 구체적인 예외가 있으며, 이에 대해 복구하기 위한 동일한 구체적인 계획이 있습니다. 따라서 각 경우에 대해 특정 예외만 처리합니다.

하지만 우리가 모든 것을 잡는다면, 우리가 복구할 준비가 된 예외 사항들에 추가로, 예상치 못한 예외 사항이 발생할 가능성도 있습니다. 그리고 그러한 예외 사항은 실제로 복구해서는 안 될 수도 있습니다.

위에서 소개한 구성 파일 예제를 살펴 봅시다. 파일이 없는 경우, 우리는 기본 설정을 적용하고 나중에 자동으로 구성을 저장할 것을 결정할 수 있습니다(다음에는 파일이 존재합니다). 이제 서 습득힌 것처럼 IsADirectoryError, PermissionError 같은 예외가 발생합니다. 이 경우, 계속하길 원치 않을 것입니다. 여전히 기본 설정을 적용할 수는 있지만, 나중엔 파일을 저장할 수 없습니다. 그리고 사용자가 기본 설정 대신 사용자 설정을 원할 확률이 높습니다. 그래서 우리는 즉시 사용자에게 알리고, 가능하면 프로그램 실행을 중단할 것입니다. 그러나 이것은 어떤 작은 코드 부분에서 깊숙이 처리하길 원하지 않는 것입니다. 이것은 응용 프로그램 수준에서 중요한 문제이므로 상위 수준에서 처리되어야합니다. 따라서 예외를 던지게끔 합시다.

또 다른 간단한 예는 Python 2 idioms 문서에서 언급됩니다. 여기서 코드 내부의 간단한 오타 때문에 코드가 중단됩니다. 우리는 모든 예외를 잡기 때문에 NameErrors와 #$SyntaxErrors도 잡아냅니다. 이 둘은 프로그래밍 중에 우리 모두가 겪는 실수이며, 배포할 때 반드시 포함하고 싶지 않은 실수입니다. 그러나 우리가 그것들을 잡아내기 때문에, 그것이 발생할 때 우리는 제대로 디버깅하기 위한 어떠한 도움도 받을 수 없고, 그것이 발생했다는 것을 알지 못하게 됩니다.

하지만 준비하기 어려운 더 위험한 예외 상황도 있습니다. 예를 들어, SystemError는 대개 드물게 일어나는 것이며 실제로 준비할 수 없습니다. 이는 무언가 더 복잡한 상황이 일어나고 있으며, 현재 작업을 계속할 수 없는 것일 가능성이 높습니다.

어떤 경우에도, 코드 작은 부분에서 모든 것을 준비할 수 있을 가능성은 매우 적습니다. 따라서 정말 준비한 예외만 잡아야 합니다. 몇몇 사람들은 Exception 를 적어도 잡아야 한다고 제안합니다. 왜냐하면 이는 temExit and 나 boardInterrupt which 와 같은 것들을 포함하지 않기 때문입니다. 디자인 상으로는 애플리케이션을 종료시키기 위한 예외입니다. 하지만 이는 여전히 너무 난해합니다. 개인적으로는 전역 애플리케이션 수준 예외 처리기에서 Exception 또는 어떤 예외도 잡는 것만 받아들이는데, 이 예외 처리기는 준비하지 않은 예외를 기록하는 하나의 목적만 있습니다. 이렇게 함으로써 예상치 못한 예외에 대한 정보를 최대한 보존하면서 이를 명시적으로 처리하기 위해 우리의 코드를 확장할 수 있습니다(복구할 수 있는 경우). 또는 버그인 경우, 다시 일어나지 않도록 테스트 케이스를 만들기 위해 사용할 수 있습니다. 하지만, 우리가 이미 예상한 예외만 잡은 경우에만 이것이 작동하므로 예상치 못한 경우는 당연히 상위로 올라갈 것입니다.

except 블록에서는 지나치게 전달하지 않도록 노력하십시오.

명시적으로 특정한 일부 예외를 잡을 때 아무것도 하지 않고 그냥 넘어갈 수 있는 상황이 많습니다. 이러한 경우에는 # $ # & *! & $ $ & 가 있으면 충분합니다. 하지만 대부분의 경우에는 이러한 처리 과정에 관련된 코드가 필요하기 때문에 그런 경우가 아닙니다(위에서 언급했듯이). 예를 들어, 작업을 다시 시도하거나 기본 값을 설정하는 것과 같은 것입니다.

하지만 그렇지 않은 경우도 있습니다. 예를 들어, 우리의 코드가 이미 성공할 때까지 반복되도록 구성되어 있다면, 그냥 통과하는 것만으로 충분합니다. 위의 예제를 가져와서, 우리는 사용자에게 숫자를 입력하도록 요청할 수 있습니다. 사용자가 요청한 대로하지 않기 때문에, 처음부터 그것을 루프에 넣어서 다음과 같이 보일 수 있습니다.

def askForNumber ():

while True:

try:

return int(input('Please enter a number: '))

except ValueError:

pass

우리는 예외가 발생하지 않을 때까지 계속 시도하기 때문에 except 블록에서 특별히 할 일이 없으므로 이것은 괜찮습니다. 그러나 물론 사용자에게 입력을 반복해야 하는 이유를 알려주기 위해 어떤 오류 메시지를 보여주는 것이 좋다고 주장할 수 있습니다.

하지만 많은 경우에, except을 전달하기만 해도 우리가 잡은 예외에 대해 준비가 되지 않았다는 신호입니다. 예외가 간단한 경우 (예: ValueError 또는 TypeError )이고 전달하는 이유가 명확하다면 전달하는 것을 피하십시오. 정말로 할 것이 없으면 (그것이 확실하다면), 그러한 경우에 대한 설명을 추가하는 것을 고려하십시오. 그렇지 않으면 except 블록을 확장하여 실제로 복구 코드를 포함하도록하십시오.

except: pass

하지만 가장 나쁜 경우는 둘의 조합입니다. 이는 우리가 그 어떤 에러든 자발적으로 받아들이고 있지만 (어떤 에러든 대비하지 않았기 때문에) 아무런 조치도 취하지 않는다는 것을 의미합니다. 최소한 에러를 로그에 기록하고 확실히 애플리케이션을 종료하도록 재발생 시켜야 합니다 (MemoryError 이후로 정상적으로 계속하기 어렵기 때문에). 그냥 넘어가면 (물론 어디에서 catch하는지에 따라 달라질 수 있음) 애플리케이션을 어느 정도 살려두지만 오류를 발견하지 못하게 되어 모든 정보를 버리게 됩니다. 이것은 당신이 그 오류를 발견한 사람이 아닌 경우 특히 그렇습니다.

그래서 결국은: 당신이 진짜 예상하고 복구할 준비가 된 예외만 잡으세요. 그 외의 경우는 고쳐야 할 오류이거나 아무것도 준비하지 않은 것일 가능성이 높습니다. 특정 예외를 전달하는 것은 그 예외에 대해 무언가를 처리하지 않아도 되는 경우에만 좋습니다. 그 외의 모든 경우에는 건담하고 게으른 표시입니다. 그리고 당신은 그것을 고치고 싶을 것입니다.

답변 2

except: pass는 안 좋은 프로그래밍 습관입니다. 이유는 다음과 같습니다.

except: pass는 예외 처리를 제대로 하지 않는 코드입니다. 예외 처리는 프로그램에서 중요한 역할을 합니다. 예외 처리가 제대로 이루어지지 않으면, 프로그램이 예상치 못한 방식으로 작동할 수 있습니다. 그리고 이를 감지하기가 어려울 수 있습니다. 따라서 코드의 완성도와 안정성을 높이기 위해서는 예외 처리를 확실히 해주어야 합니다.

except: pass는 디버깅을 어렵게 만듭니다. 예외 처리가 부적절하게 이루어지면, 디버깅이 매우 어려워집니다. 따라서 개발자는 코드에 대한 신뢰도를 잃게 됩니다. 이 문제를 해결하기 위해서는 예외 처리를 명확하게 하여 좀 더 정확한 디버깅을 할 수 있게 해주어야 합니다.

except: pass는 버그의 원인이 됩니다. 예외 처리가 부적절하게 이루어진 코드에서는 예상치 못한 결과가 나타날 수 있습니다. 이는 프로그램에서 버그를 발생시킬 가능성이 큽니다. 그러므로 예외 처리를 명확하게 하여 프로그램의 안정성을 유지해야 합니다.

결론적으로, except: pass는 안 좋은 프로그래밍 습관입니다. 이를 해결하기 위해서는 예외 처리를 확실히 하여 프로그램의 안정성과 신뢰도를 높이도록 노력해야 합니다.

반응형
Comments