본문 바로가기
#단편모음/낱 장

[혼공파] C06 예외처리-230521日

by taeni 2024. 4. 16.

C06 예외 처리

06-1 구문 오류와 예외

06-2 예외 고급


06-1 구문 오류와 예외       (p.291 마무리)

구문 오류는 프로그램의 문법적인 오류로 프로그램이 실행조차 되지 않게 만드는 오류입니다.

예외(런타임 에러)는 프로그램 실행 중에 발생하는 오류입니다. try catch 구문 등으로 처리할 수 있습니다. 반대로 구문 오류는 실행 자체가 안되므로 try catch 구문으로 처리할 수 없습니다.

기본 예외 처리는 조건문 등을 사용해 예외를 처리하는 기본적인 방법입니다.

try except 구문은 예외 처리에 특화된 구문입니다.

 

06-2 예외 고급   (p.307 마무리)

예외 객체는 예외와 관련된 정보를 담고 있는 객체입니다.

raise 구문은 예외를 강제로 발생시킬 때 사용하는 구문입니다.

GitHub 검색은 많은 사람이 함꼐 개발하는 소셜 코딩 사이트 GitHub을 이용하는 것으로, 유능한 개발자들의 정제된 코드를 살펴볼 수 있습니다.


06-1 구문 오류와 예외

오류의 종류

프로그래밍 언어의 오류error에는 크게 두 가지 종류가 있습니다.

  • 프로그램 실행 에 발생하는 오류  👉 구문 오류syntax error라고 부르며
  • 프로그램 실행 에 발생하는 오류  👉 예외exception,  런타임오류runtime error 라고 구분한다.

두 가지 모두 '오류'라고 부릅니다. 

 

● 구문 오류

구문 오류는 괄호의 개수, 들여쓰기 문제 등으로 인해 프로그램이 실행되기도 전에 발생하는 오류

+ EOL : End Of Line : 마지막줄(막줄)

+ SyntaxError : 구문에 문제가 있어 프로그램이 실행조차 되지 않는 오류

 

● 예외

예외 또는 런타임 오류는 실행 중에 발생하는 오류

 

기본 예외 처리

예외를 해결하는 모든 것을 예외 처리exception handling라고 부릅니다. 예외를 처리하는 방법은 다음 두 가지로 나뉘게 된다.

  • 조건문을 사용하는 방법    👉 이와 같은 예외 처리 방법을 기본 예외 처리라고 부른다.
  • try 구문을 사용하는 방법  👉 

+ 구문 오류는 프로그램이 실행조차 되지 않기 때문에 예외 처리 방법으로 처리할 수 없다. 문법적이 문제가 발생한 코드를 수정해 주어야 한다.

 

 

 

● 예외 상황 확인하기

 

● 조건문으로 예외 처리하기

위의 코드에서 정수를 입력하지 않으면 문제가 발생하게 된다. 따라서 '정수를 입력하지 않았을 때'를 조건으로 구분해서 해당 상황일 때 다른 처리를 하도록 설정해보자.

 

아래 코드는 문자열의 isdigit() 함수를 사용해서 숫자로만 구성된 글자인지 확인한다. 👉 이렇게 하면 int() 함수를 이용해 숫자로 변환할 수 없는 문자열을 변환하면서 발생하는 예외를 피할 수 있게 된다.

 

정수로 변환할 수 없는 문자열을 입력하더라도, ①isdigt()함수를 사용해 숫자로 구성되어 있지 않다는 것을 확인하고 ②else 구문 쪽으로 들어가서 "정수를 입력하지 않았다."라는 문자열을 출력하게 된다. 

👉 프로그램이 중간에 강제로 죽지 않고 정상으로 종료된다. 

try except 구문

(역사) 초기의 프로그래밍 언어는 조건문만으로 예외를 처리했다. 하지만 예외가 발생한 상황을 예측하고 모두 조건문으로 처리하는 것은 매우 힘든 일이다. 프로그래밍 언아의 구조적인 문제로 인해 조건문만으로 예외를 처리할 수 없는 경우도 있다.

 

(so, Now)그래서 요즘 프로그래밍 언어는 예외를 처리할 수 있는 구문을 제공한다. 바로 try except구문이다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	예외가 발생했을 때 실행할 코드

어떤 상황에 예외가 발생하는지 잘 이해하고 있지 않아도 프로그램이 강제로 죽어 버리는 상황을 막을 수 있다.

● try except 구문과 pass 키워드 조합하기

프로그래밍을 하다 보면 정확한 오류 원인을 잡지는 못하더라도 어떤 부분에서 예외가 발생하는지 정도는 파악할 수 있는 상황이 있다. 예외가 발생하면 일단 처리해야 하지만, 해당 코드가 딱히 중요한 부분이 아니라면 일단 프로그램이 강제 종료되는 것부터 막자는 목적으로 except구문에 아무것도 넣지 않고 try 구문을 사용하게 됩니다.  ※하지만! 구문 내부에 아무 것도 넣지 않으면 구문 오류가 발생하기 때문에 다음과 같이 pass키워드를 넣어 주어 사용한다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	pass

예외를 잘 활용하면 간단한 코드로 필요한 기능을 구현할 수 있다.

숫자료 변환할 수 없는 문자열이라면 float(item)를 싱행할 때 예외가 발생한다. 따라서 이를 이용해서 try except 구문으로 감싸고 예외가 발생하지 않는 경우에만 list_number.append(item)가 실행되도록 만든 코드이다.

 

(속도면에서) + 물론 try except 구문은 if구문을 활용하는 코드에 비해 아주 약간 느리다. 하지만 필자는 파이썬 자체가 그렇게 속도를 중시하는 프로그램이 언어가 아니므로 코드를 조금 더 쉽게 작성할 목적이라면 사용해도 괜찮다고 보고 있다.

 

try except else 구문

try exept 구문 뒤에 else 구문을 붙여서 사용하면 '예외가 발생하지 않았을 때 실행할 코드'를 지정할 수 있다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	예외가 발생했을 때 실행할 코드
else:
	예외가 발생하지 않았을 때 실행할 코드

try exept else 구문은 사용할 때는 예외가 발생할 가능성이 있는 코드만 try 구문 내부에 넣고 나머지를 모두 else구문으로 빼는 경우가 많다.

finally구문

finally 구문은 예외 처리 구문에서 가장 마지막에 사용할 수 있는 구문입니다.

예외가 발생하든 발생하지 않든 무조건 실할 때 사용하는 코드입니다.

try:
	예외가 발생할 가능성이 있는 코드
except:
	예외가 발생했을 때 실행할 코드
else:
	예외가 발생하지 않았을 때 실행할 코드
finally:
	무조건 실행할 코드

 정수를 입력하든 문자열을 입력하는 경우든 두 가지 경우 모두 "일단 프로그램이 어떻게든 끝났습니다.'라고 finally 구문이 실행되는 모습을 볼 수 있다.

 

● try, except, finally 구문의 조합

예외 처리 구문은 다음과 같은 규칙을 지켜야 한다.

  • try 구문은 단독으로 사용할 수 없으며, 반드시 except구문 또는 finally구문과 함꼐 사용해야 한다.
  • else구문은 반드시 except구문뒤에 사용해야 한다.

이를 조합해 보면 다음 표와 같이 나온다.

1. try + except 구문 조합
2. try + except + else 구문 조합
3. try + except + finally 구문 조합
4. try + except + else + finally 구문 조합
5. try + finally 구문 조합

이 외의 조합은 실행했을 때 구문 오류가 발생한다.  구문 오류가 발생하면 아얘 실행되지도 않는다.

 

● try, except, finally 구문의 조합

일반적으로 finally 키워드를 설명하는 예제로 '파일 처리'를 많이 사용한다.

 

파일을 열고 있으면 해당 파일을 이동하거나 덮어 씌우거나 하는 것이 불가능해진다. 따라서 프로그램에서 파일을 열었으면oepn 무조건 닫아야close 한다. 파일을 제대로 닫았는지는 파일 객체의 closed 속성으로 알 수 있다.

 

물론 아래의 예제처럼 간단하게 실행되고 끝나느 프로그램이라면 큰 상관은 없다. 프로그램이 끝날 때 자신이 열었던 파일을 자동으로 모두 닫기 때문이다. 하지만 이 프로그램이 항상 켜져 있는 프로그램이라면 문제가 생길 수 있다.

 

(note)항상 켜저 있는 프로그램을 데몬demon 또는 서비스service라고 부른다. 예를 들어 컴퓨터의 성능을 감시하느 프로그램, 파일의 변경을 감시하는 프로그램, 사용자에게 웹 페이지를 제공해 주는 웹 서버 등이 모두 데몬이자 서비스이다.

 

파일을 닫을 때는 close()함수를 사용한다. 그런데 중간 과정에서 예외가 발생해서 try 구문 중간에 튕겨 버리면 파일이 제대로 닫히지 않는 문제가 발생할 수 있다.

아래의 오른쪽 사진 처럼, 그냥 try except 구문이 모두 끝난 후에 파일을 닫아도 아무 문제가 없다.

 

finally 키워드는 어떤 조건에 무조건 사용해야 하는 것이 아니라 finally를 사용하면 코드가 깔끔해질 것 같다고 생각하는 경우에 사용한다.

 

● try 구문 내부에서 return 키워드를 사용하는 경우

finally 구문은 반복문 또는 함수 내부에 있을 때 위력을 발휘한다.

try 구문 내부에 return 키워드가 있다는 것이 포인트이다. try 구문 중간에 탈출해도 finally 구무는 무조건 실행된다. 따라서 함수 내부에서 파일 처리 코드를 깔끔하게 만드록 싶을 때 finally구문을 활용하는 경우가 많다. try 구문에서 원할 때 return 키워드로 빠져나가도 파일이 무조건 닫히기 때문이다.

만약 중간에 return 키워드 등으로 함수를 빠져나갈 때마다 close()를 하도록 코드를 작성했다면 코드가 굉장히 복잡해질 것이다. 하지만 위처럼 finally 구문에서 close()함수를 호출하도록 작성하면 코드가 깔끔해진다.

 

● 반복문과 함께 사용하는 경우

finally 구문은 무조건 실행된다, 따라서 반복문에서 break로 빠져나갈 때도 마찬가지이다. 

break 키워드로 try 구문 전체를 빠져나가도 finally 구문이 실행되는 것을 볼 수 있다.


06-2 예외 고급

과 같은 

현실에서 어떤 사건이 발생하면 '누가, 언제, 어디서'라는 정보가 생긴다.

프로그래밍 언어도 예외가 발생하면 예외와 관련된 정보가 생기게 된다.

그리고 이러한 예외 정보는 예외 객체exception object에 저장된다.

 

예외 객체의 형태

try:
	예외가 발생할 가능성이 있는 구문
except: 예외의 종류 as 예외 객체를 활용할 변수 이름:
	예외가 발생했을 때 실행할 구문

예외 객체

모든 예외의 어머니 : Exception

(note) Exception 은 '클래스'이다. 

예외 객체의 자료형은 Value Error, 내용은 invalid literal for int() with base 10: ' <입력한 문자열'>이 출력되게 된다.

 

만약 큰 규모의 웹 서비스를 구축한다면 내부에서 다양한 예외가 발생한다. 예외가 발생할 떄 이러한 정보를 메일 등으로 보내도록 해서 수집하면 이후에 프로그램을 개선하는 데 큰 도움이 된다.

 

예외 구분하기

예외 객체를 사용하면 except 구문을 if 조건문처럼 사용해서 예외를 구분할 수 있다.

● 여러 가지 예외가 발생할 수 있는 상황

 예외 구분하기

파이썬은 except 구문 뒤에 예외의 종류를 입력해서 예외를 구분할 수 있다.

try:
	예외가 발생할 가능성이 있는 구문
except 예외의 종류A:
	예외A가 발생했을 때 실행할 구문
except 예외의 종류B:
	예외B가 발생했을 때 실행할 구문
except 예외의 종류C:
	예외C가 발생했을 때 실행할 구문

● 예외 구분 구문과 예외 객체

예외를 굽준할 떄 각각의 except 구문 뒤에 예외 객체를 붙여 활용할 수도 있다.

마찬가지로 as 키워드를 사용하면 된다.

모든 예외 잡기

except 구문으로 예외를 구분하면 ☞ if, elif, else 조건문처럼 차례대로 오류를 검출하면서 확인한다.

만약 예외 조건에 일치하는 것이 없다면 당연히 예외가 발생하며 프로그램이 강제로 종료된다.

 

예를 들어 아래의 코드를 살펴보면, 중간에 "예외.발생해주세요()"를 사용하는데, '예외'라는 이름의 변수가 없으므로 예외가 발생한다. 이름이 없으므로 NameError가 발생하는데, 에외 처리 구분 중에 NameError가 없다.

이렇게 되면 예외가 발생해 프로그램이 강제 종료된다.

그래서 else 구문처럼 마지막에는 모든 예외의 부모라고 할 수 있는 Exception을 넣어서 프로그램이 죽지 않게 하는 것이 좋은 방법이다. ( 위 오른쪽 사진 )

 

+ 참고로 너무 치명적인 문제인데도 프로그램이 종료되지 않게 만들면 그건 또 그것대로 문제가 될 수 있으므로 상호아을 꼭 확인하도록 한다.

 

 예외 처리에서 가장 중요한 것은 '이 코드에서 어떤 예외가 발생할 것인가?'를 잘 예측하는 것이다.모든 것을 예측한다는 것은 절대 쉬운 일이 아니고 그럴 수도 없지마, 최대한 잡을 수 있는 것들을 예측해 보고 잡을 수 있도록 노력하는 것이 개발자의 자세라고 할 수 있다.

 

raise 구문

프로그램이 강제 종료되는 것을 막기 위해 예외는 꼭 처리해야 한다. 하지만 프로그램을 갭라하는 동안에는 '아직 구현하지 않은 부분이니까 확실하게 문제가 생기게 만들자' or '이 부분을 그냥 넘어가면 나중에 큰 문제가 생기게 되니 여기에서 강제 종료 시키자'는 경우도 있다.

👉 (종합) 아직 구현되지 않은 부분이므로 일부러 예외를 발생시켜 프로그램을 죽게 만들어 잊어버리지 않도록 하는 것이다.  ✏️이때 사용한 raise 키워드가 바로 예외를 강제로 발생시키는 기능을 한다.

raise 예외 객체

사용방법 : raise  + 예외 이름 입력

 

이때 출력되는 메시지를 원하는 형태로 만들고 싶다면 예외 클래스를 만들어야 한다. 사용빈도가 높은편은 아닌데, 이와 관련된 내용은 8장에서 클래스를 배우며 살펴보도록 하겠다.

 

'#단편모음 > 낱 장' 카테고리의 다른 글

[혼공파] C08 클래스-230608木  (0) 2024.04.16
[혼공파] C07 함수-230601木  (0) 2024.04.16
[혼공파] C05 함수-230516火  (0) 2024.04.16
[혼공파] C04 반복문-230515月  (0) 2024.04.16
[혼공파] C03 조건문-230512金  (0) 2024.04.16