본문 바로가기

Programing/Python

[Python 입문] 17. 파이썬 오류와 예외처리 (2)

목차

  • 오류의 예외처리 기법
  • 오류 회피하기
  • 오류 일부러 발생시키기

파이썬의 예외처리

오류의 예외처리 기법

 앞서 알아본 프로그래밍의 오류에 대한 처리 기법을 알아보자. 많은 프로그래밍 언어(Java, C++ 등)에서는 예외를 처리할 수 있는 exception 문법을 제공한다. 파이썬에서는 try와 except문을 제공한다

 

1. try, except문

 아래는 try, except문의 기본 구조이며 try 블록 수행 중 오류가 발생하면 except 블록이 실행된다. 단, try 블록에서 오류가 없다면 당연히 except 블록은 실행되지 않는다.

try:
    ...
except [발생 오류[as 오류 메시지 변수]]:
    ...

 위 예시에 있는 대괄호 [ ]를 사용하고 있는데 이 기호는 괄호 안의 내용을 생략할 수 있다는 관례적인 표기법이다. 

 

 아래와 같은 예시를 보면 쉽게 이해할 수 있을 것이다.

try:
    something1()
    something2() --> 예외 발생
    something3()
    something4()

except :
    print("예외 발생!")

 예를 들어서 try 블록 안에서 함수 4개를 실행할 때. something2이라는 함수에서 예외가 발생하면, 그 즉시 실행을 멈추고 except로 넘어간다. 만약 이 예외가 except 하고자 하는 예외(<예외 이름>)과 같다면, 예외처리 블록의 print("예외 발생!")을 실행하고, 아니라면 해당 예외를 처리하지 않는다. 그리고 처리되지 않은 예외는 이 함수를 call 한 함수로 전이(propagate)된다.

 

 이런 except 구문은 다음과 같은 방법으로 사용할 수 있다.

# 1. try, except만 쓰는 방법
try:
    prin()
except :
    print("예외 발생!")

실행 결과: 
예외 발생!


# 2. 발생 오류만 포함한 except문
try:
    prin("3")
except NameError:
    print("예외 발생!")

실행 결과:
예외 발생!


# 3. 발생 오류와 오류 메시지 변수까지 포함한 except문
def main():
    try:
        prin("3")
    except NameError as e:
        print("예외 발생! main ", e.args)
        print(e.__traceback__)
main() 

실행 결과:
예외 발생! main ("name 'prin' is not defined",) 
<traceback object at 0x100764208>

 1. try, except만 쓰는 방법으로 오류 종류에 상관없이 오류가 발생하기만 하면 except 블록을 실행하다.

2. 발생 오류만 표함한 except문의 경우 오류가 발생했을 때 except문에 미리 정해둔 오류 이름과 일치할 때만 except블록을 실행한다.

3. 발생 오류와 오류 메시지 변수까지 포함한 except문의 경우 두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용하는 방법이다.

 

 앞선 설명에서와 같이 어떤 경우에 예외 전이가 될까?

try:
    prin("3")
except EOFError:
print("예외 발생!") 

실행 결과: 
Traceback (most recent call last): 
  File "/jump_to_python/05/Error.py", line 2, in <module> 
    prin("3") 
NameError: name 'prin' is not defined

 위와 같이 prin("3")에서 NameError가 난다. 하지만 NameError를 예외처리 하지 않으므로 예외가 전이(propagate)된다.

 예외의 전이(Exception Propagation)란, 예외가 발생한 부분이 해당 예외를 처리하지 않는 경우 이 예외를 부른 함수로 예외가 전달되는 것을 의미한다

 

def doSomething ():
    print("1")
    print("2")
    prin("3")   <---- 예외 발생
    print("4")

def main():
    try:
        doSomething()
    except NameError:
        print("예외 발생! main")

main() 

실행 결과: 
1
2
예외 발생! main

 위의 예를 보면 예외는 doSomething안에서 발생하다. 하지만 doSomething안에는 예외를 처리하는 except구문이 없다. 따라서 이 예외는 doSomething을 부른 main 함수로 전이(propagate)되고 main에서 NameError를 처리하기 때문에 "예외 발생! main"이 출력된다.

 

2. try .. else

 try문은 else 블록(절)을 지원한다. else블록은 예외가 발생하지 않은 경우에 실행되고, 반드시 except 블록 바로 다음에 위치해야 한다.

try:
    f = open('foo.txt', 'r')

except FileNotFoundError as e:
    print(str(e))
else:
    data = f.read()
    f.close()

 위 예시를 보면 만약 foo.txt. 파일이 없다면 except 블록이 실행되고, foo.txt 파일이 있다면 else 블록이 실행된다.

 

3. try .. finally

 try문에는 finally 블록을 사용할 수 있다. finally 블록은 try문 실행 도중 예외 발생 여부에 상관없이 항상 실행된다. 보통 finally 블록은 사용한 리소스를 close 해야 할 경우에 많이 사용한다.

f = open('foo.txt', 'r')
try:
    # 무언가 수행
finally:
    f.close()

 foo.txt 파일을 쓰기 모드로 연 후 try문이 수행된 후 예외 발생 여부와 상관없이 finally 블록에서 열린 파일을 닫을 수 있다.

 

 

오류 회피하기

 프로그래밍을 하다보면 특정 오류가 발생할 경우 무시하고 통과시켜야 할 때가 있을 수 있다.

try:
    f = open("asd.txt", 'r')
except FileNotFoundError:
    pass

 위 예시를 보면 try문 내에서 FileNotFoundError가 발생할 경우 pass를 사용해 오류를 회피하도록 한다.

 

 

일부러 오류 발생시키기

 프로그래밍을 하다보면 종종 오류를 일부러 발생시켜야 할 경우도 있다. (아직은 이해하기 어렵다...) 이럴 때 파이썬에서는 raise라는 명령어로 오류를 강제로 발생시킬 수 있다.

 

 먼저 아래와 같이 Bird라는 클래스를 만들어보자. (NotImplementedError는 파이썬의 내장 오류로, 꼭 작정해야 하는 부분이 구현되지 않을 경우 일부러 오류를 발생시킬 때 사용한다.) 그리고 Bird 클래스를 상속받는 Eagle 클래스를 만들고, fly함수를 따로 구현하지 않은 상태에서 fly함수를 호출해보자.

class Bird:
    def fly(self):
        raise NotImplementedError

class Eagle(Bird):
    pass

eagle = Eagle()
eagle.fly()

 

Eagle 클래스는 Bird 클래스를 상속받았지만 Eagle 클래스에서 fly함수를 구현하지 않았기 때문에 당연히 Bird 클래스의 fly 함수가 호출된다. 하지만 raise문에 의해 아래와 같이 NotImplementedError가 발생한다.

Traceback (most recent call last):
  File "/jump_to_python/05/Error.py", line 28, in <module>
    eagle.fly()
  File "/jump_to_python/05/Error.py", line 22, in fly
    raise NotImplementedError
NotImplementedError

 

 위와같이 오류가 발생되지 않게 하려면 아래와 같이 Eagle 클래스에 fly함수를 별도로 구현해야 한다.

class Eagle(Bird):
    def fly(self):
        print("very fast")

eagle = Eagle()
eagle.fly()

very fast

 그러면 위의 마지막 문장과 같이 오류 없이 정상적으로 문장이 출력된다.

 

 

내용 출처: 책 '점프 투 파이썬'의 내용

https://imasoftwareengineer.tistory.com/64?category=769846