본문 바로가기

Program Languages/Python

파이썬 에러 핸들링 문법 사용법

이번 포스트에서는 파이썬에서 코드에서 에러가 발생했을 때, 강제적으로 프로세스를 종료되지 않고 코드 내부에서 에러를 핸들링하는 문법을 알아보고자 합니다.

 

에러를 코드내에서 처리해야하는 경우는 많은 경우가 있지만 대략 아래와 같을 겁니다.

  1. 디스크 쓰기 및 읽기도중 하드웨어에서 오류가 발생했거나 소켓등 통신관련 코드의 오류 확인 및 처리가 필요한  경우
  2. 쿼리문 문법의 한계등으로 파이썬 수준에서 에러 핸들링이 필요한 경우
  3. 기타 여러 소프트웨어나 하드웨어에서 오류가 발생했지만 프로세스 전체가 종료되기를 원치 않고 특정 코드에 대해서만 오류를 처리하고 싶은 경우
  4. 디버깅이 일시적으로 필요한 경우
  5. 기타 여러 경우

파이썬 코드 내에서 에러를 핸들링하는 기본적인 문법은 아래와 같습니다.

try:
    print("[try")
    에러발생=[True,False]
    print("*"*3,("에러가 발생하는 경우" if(sum(에러발생)>0) else "에러가 발생하지 않는 경우"),"*"*3)
    if(에러발생[0]==True):
        raise Exception("가상 에러") from IOError #Exception이라는 에러를 강제적으로 발생시키는 코드, 이 줄 코드에서 IOError는 Exception("가상 에러")가 발생하는 본질적인 원인이라고 문법적으로 명시   
    	#만약 문법이 raise None from IOError 이면, 발생된 에러를 IOError로 인식
        
        """
        즉,raise <에러 클래스1> from <에러 클래스2> 이라면 <에러 클래스1>라고 인식하기에 큰 문제가 없으면 <에러 클래스1>로 1순위로 인식, <에러 클래스1>에 문제가 있으면 <에러 클래스2>를 2순위로 인식함 
        이때, 'from <에러 클래스2>'는 문법적으로 생략가능
        즉, 'raise <에러 클래스1>' 만으로도 에러발생이 가능
        """
    if(에러발생[1]==True):
        raise StopIteration()#StopIteration이라는 에러를 강제적으로 발생시키는 코드
    
except StopIteration:
    #try문 전체 코드가 완료되기 전까지 StopIteration이라는 에러가 발생하면 아래 문을 실행
    print("StopIteration?")
except IOError as ioE:#IOError이라는 에러 변수에 접근할 수 있는 별칭을 함께 명시('ioE = getIOError()' 와 비슷)
    #try문 전체 코드가 완료되기 전까지 IOError이라는 에러가 발생하면 아래 문을 실행
    print("IOError?",ioE)
except Exception:#as exception
    #try문 전체 코드가 완료되기 전까지 Exception 혹은 Exception을 상속하는 에러가 발생하면 아래 문을 실행
    print("Exception?")
else:
    #try문 전체 코드가 완료되기 전까지 파이썬에서 핸들링할 수 있는 어떤 에러도 발생하지 않았다면, try문 코드가 완료 된후 실행
    print("else?")
finally:
    #try문에서 에러가 발생여부에 상관없이 try문에 관련된 코드들이 모두 실행이 완료되면 아래 문을 실행
    print("finally?")
    print("]")

위의 결과로 보아 에러가 발생하면 해당 에러에 맞는 구문을 찾아가 실행하고 에러가 발생하지 않으면 else구문을 실행하는 것을 알 수 있었습니다.


이때 에러발생[1]=True로 변경하고, except Exception:#as exception 구문과 except StopIteration: 구문의 위치를 바꾸어 보면 어떻게 될까요?

즉,

try:
    ...
    에러발생=[False,True]
    ...
except Exception:#as exception
    #try문 전체 코드가 완료되기 전까지 Exception 혹은 Exception을 상속하는 에러가 발생하면 아래 문을 실행
    print("Exception?")
except StopIteration:
    #try문 전체 코드가 완료되기 전까지 StopIteration이라는 에러가 발생하면 아래 문을 실행
    print("StopIteration?")
...

의 형식으로 코드를 일부 변경하게 되면,

StopIteration에 대한 구문을 처리하지 않고 Exception에 관한 구문을 처리한 것을 알 수 있습니다.

 

이것으로 같은 except 구문이라면 절차적으로 첫번째 구문부터 확인하고 순차적으로 마지막 구문까지 확인한다는 것을 알 수가 있습니다.

 

 


그런데 여기서 순차적으로 확인한다고 해도 왜 stopiteration 오류처리 구문이 아니라 exception 관련 구문으로 처리가 되었을까요?

 

그이유는 바로 stopiteration클래스가 exception 클래스를 상속하고 있기 때문입니다.(클래스 상속(class inheritance)에 대한 추가적인 내용은 클래스와 관련되었으니 이 포스트에서는 생략하겠습니다.)

 

파이썬에서는 해당 클래스가 어떤 클래스에 대해 상속했는지에 대한 여부를 알려주는 함수가 기본적으로 구현되어 있습니다.

바로 issubclass(클래스_상속되었다고_추측되는_클래스명,클래스_상속_여부_의_기준_클래스명)->bool 입니다.

 

issubclass는 쉽게 설명하면 기능적으로 두 클래스간의  클래스 상속의 관계가 성립하냐를 반환해주는 함수라고 할 수 있겠습니다.

 

다시 본론으로 돌아와 StopIteration클래스와 Exception의 클래스상속관계를 확인해보겠습니다.

이것으로 보아 Exception는 StopIteration을 클래스 상속하지 않았지만 StopIteration은 Exception을 클래스 상속한 것을 알 수 있습니다.

 

따라서 '순차적으로 exception관련 구문이 다른 에러처리 구문보다 위쪽에 있으면, exception을 상속한 에러처리관련 구문은 exception 구문이 우선적으로 처리된다' ,

 

즉, 'except문에서 클래스 상속관계의 부모 그 이상에 해당하는 클래스관련 구문이 순차적으로 먼저 있으면 그것을 우선한다'는 것을 알 수 있었습니다.