Python/파이선과 친해지기

[Python] - Python과 매우 친해지기-예외처리

프로그램 포스팅을 따라오면서 수많은 ERROR를 확인했을 것이다. 프로그래밍은 에러와 프로그래머의 싸움이다. 물론 코딩을 할 때는 싸워도 된다. 그러나 프로그램을 배포를 할 때나 동작을 확인하고 싶은데 계속되는 에러로 프로그램이 계속 멈추는 것을 보고 싶은 사람은 없을 것이다.


try ~ except ~ finally

따라서 프로그램에 실행되는 도중 에러를 적절한 방법으로 처리해서 안정적인 프로그램을 만드는것은 매우 중요한 일이다. 뭐 간단하게 다음 에러로 에러에 대해서 일단 알아보도록 하자

### except.py ###

if __name__ == "__main__" :

    while(True) :
        user_input = int(input("100을 다음 수로 나눕니다. : "))

        print(100//user_input)
        print("다시 입력해주세요!")
        
출력 : 
100을 다음 수로 나눕니다. : 3
33
다시 입력해주세요!
100을 다음 수로 나눕니다. : 0
Traceback (most recent call last):
  File "C:/Users/82109/Desktop/student.py", line 8, in <module>
    print(100//user_input)
ZeroDivisionError: integer division or modulo by zero

위 코드에서 user_input이 0이되면 ZeroDivisionError로 print("다시 입력해주세요!")는 실행되지 않는다. 이러한 에러 또한 우리가 저번 시간에 배운 클래스이다. 또한 최상위 Exception부터 위에 있는 ZeroDivisionError 클래스까지 다음과 같은 계층구조를 가진다.

<출처 : https://w3.cs.jmu.edu/lam2mo/cs240_2014_08/lab05-exceptions.html>

이런 Exception클래스들은 try ~ except ~ finally 구문으로 적당하게 처리될 수 있다. 다음의 코드를 확인하자

### except.py ###

if __name__ == "__main__" :

    while(True) :
        user_input = int(input("100을 다음 수로 나눕니다."))

        try :
            print(100//user_input)
        except ZeroDivisionError :
            print("0으로는 나눌 수 없습니다.")
        finally :
            print("다시 입력해주세요!")

상기 코드는 보이는 것처럼 에러가 발생할 수 있는 print(100//user_input)을 try 코드블럭에 넣어두고, 이를 except으로 ZeroDivisionError가 발생하면 except 코드 블록이 실행되며, try가 실행되던 except이 실행되던 결국 finally가 실행되도록 동작한다.

 

 

에러의 처리

except 구문으로 핸들될 exception은 as 예약어로 excpetion의 별칭을 지정하고 이를 그대로 출력할 수 있다. 다음의 코드를 확인하자 

### except.py ###

if __name__ == "__main__" :

    while(True) :
        user_input = int(input("100을 다음 수로 나눕니다."))

        try :
            print(100//user_input)
        except ZeroDivisionError :
            print("0으로는 나눌 수 없습니다.")
        finally :
            print("다시 입력해주세요!")
            
출력 : 
100을 다음 수로 나눕니다.0
integer division or modulo by zero
다시 입력해주세요!
100을 다음 수로 나눕니다.

또한 에러처리에 관련해서는 다음과 같은 방법 또한 사용된다.

### except.py ###

if __name__ == "__main__" :

    while(True) :
        user_input = int(input("100을 다음 수로 나눕니다."))

        ## 에러처리1 ##
        try :
            print(100//user_input)
        except (ZeroDivisionError, ValueError) :
            
            print("이상한 값인듯 싶네요.")

        ## 에러처리2 ##
        try :
            print(100//user_input)
        except Exception as e:
            print(e)

        ## 에러처리3 ##
        try :
            print(100//user_input)
        except (ZeroDivisionError, ValueError) :
            print("이상한 값인듯 싶네요.")
        else :
            print("에러가 발생하지 않았습니다.")

1. 에러처리1 처럼 여러 가지 에러를 튜플로 묶어서 핸들 할 수 있다.
2. 최상의 에러인 Exception을 묶어서 에러처리할 수 있다.(사실 추천하지는 않는다. 자세하게 어떠한 에러가 발생했는지 출력하는 것이 좋다.)
3. 마지막 else문을 이용해서 에러가 발생하지 않았을때만 처리할 구문을 쓸 수 있다.(finally와 다르다)

 

raise

에러를 강제로 발생시킬 수도 있다. 이때 에러는 이미 생성된 error class로 생성할 수도 있고, 프로그래머가 적당한 에러를 만들어 그 에러를 사용할 수도 있다. 아래는 그 예시이다.

### except.py ###

class my_error(Exception) :

    def __init__(self,expression) :
        self.expression = expression

if __name__ == "__main__" :

    while(True) :
        try :
            user_input = int(input("100을 다음 수로 나눕니다."))

            if(user_input == 0) :
                raise my_error("0을 입력하셨습니다.","0의 입력")
        except my_error as e:
            print(e)

Exception을 상속받아서 my_error 클래스를 만들었다. my_error의 생성자에는 expression만을 넣었지만, Exception에서는 내용을 의미하는 message들도 있으니, 공식 제공 문서와는 항상 친하게 지내자 또한 중간에

(참고 :  docs.python.org/3/library/exceptions.html

 


이번시간에는 프로그램의 영원한 친구인 에러를 적당하게 처리하는 방법을 알아보았다. 이제 우리 프로그램은 좀 더 안정적인 방향으로 발전하게 되었다. 다음 시간에는 여태까지 배운 예외처리와 객체지향의 특성을 이용해서 학생 관리 프로그램을 발전시켜 보자