- 예외(Exception): 프로그램의 제어 흐름을 조정하기 위해 사용하는 이벤트

- 파이썬에서는 아무런 처리를 하지 않은 예외에 대해 자동으로 에러를 발생, 사용자의 제어 흐름을 벗어나 에러문을 출력하고 프로그램을 종료함

- 일반적으로 개발툴에서는 예외가 발생하면 Standard Error를 통하여 화면에 출력

- 처리되지 않은 예외(Unhandled Exception): 비정상적인 종료를 일으키는 예외, 개발 단계에서 고려 필요


구문 에러

- 구문에러(Syntax Error)는 인터프리터에서 구문 에러가 의심되는 부분을 알려주기 때문에 쉽게 수정 가능

- 구문에러가 발생하는 경우에는 인터프리턱 지적하는 부분의 앞뒤를 모두 확인하여야 함

print("{0}, {1},format(10, 20))

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 13

    print("{0}, {1},format(10, 20))

                                  ^

SyntaxError: EOL while scanning string literal


a = 10

if a > 5 print('a is bigger than 5')


  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 18

    if a > 5 print('a is bigger than 5')

                 ^

SyntaxError: invalid syntax


예외

1. 쉽게 발생하는 예외

1) NameError

print(a)

Traceback (most recent call last):

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 21, in <module>

    print(a)

NameError: name 'a' is not defined

2) ZeroDivisionError

print("10/0:", 10/0)

Traceback (most recent call last):

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 22, in <module>

    print("10/0:", 10/0)

ZeroDivisionError: division by zero

3) IndexError

= [10, 20, 30]

print("a[3]:", a[3])

Traceback (most recent call last):

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 27, in <module>

    print("a[3]:", a[3])

IndexError: list index out of range

4) Type Error

a = 'Apple'

print("10/a:", 10/a)

Traceback (most recent call last):

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 31, in <module>

    print("10/a:", 10/a)

TypeError: unsupported operand type(s) for /: 'int' and 'str'

- 위에서 발생되는 예외들은 exceptions 모듈에 미리 저장되어있음


2. 내장 예외의 계층 구조

- 내장 이름 공간으로 이미 포함 되어 있기 때문에 임포트 하지 않아도 됨

- 내장 예외는 프로그램 동작중에 발생 할 수도 있지만 개발자가 명시적으로 예외를 발생 시킬수도 있음

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning


- 각 예외에 대한 설명은 아래서 찾아보기....


예외 처리

- try 구문: 발생 가능성이 있는 예외를 적절하게 처리 할 수 있음


1. 기본적인 try 구문

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               "finally" ":" suite


1) try: 예외 발생이 예상되는 부분에 대하여 작성

2) except: 예외 발생 시 처리를 담당하는 부분 작성, 예외 처리 방법에 따라 3가지 방식으로 작성 가능

- except <예외 종류> : 예외 처리 문장

- except (예외1, 예외2) : 예외 처리 문장

- except 예외 as 인자 : 예외 처리 문장

3) else: 예외가 발생 하지 않은 경우

4) finally: 예외 발생과 상관 없이 항상 수행

- else와 finally문은 생략 가능


2. 예외 처리 예제

1) 예외의 종류에 상관없이 동일하게 예외 처리

def divide(a, b):

    return a / b


try:

    c = divide(5, 0)

except:

    print("Exception is occured!!")

Exception is occured!!

2) 다양한 예외 처리 예제

- 각 예외에 따라 다른 처리가 필요한 경우 except 이후에 처리할 예외를 명시할 수 있음

- 발생한 예외에 대해서 except 문장을 순차적으로 검사

- 예외 처리는 반드시 좁은 범위에서 넒은 범위로 확장해야 함

def divide(a, b):

    return a / b


try:

    c = divide(5, 'string')


except ZeroDivisionError:

    print("두 번째 인자는 0이면 안됩니다.")

except TypeError:

    print("모든 인수는 숫자이어야 합니다.")

except:

    print("음~무슨 에러인지 모르겠어요!!")


모든 인수는 숫자이어야 합니다.

3) 책임 사슬(Chain of Responsibility)

- GOF 패턴 중 에러처리에 유연하게 적용할 수 있는 구조

- 에러를 해결할 수 있는 에러 처리기(error handler)가 일렬로 늘어놓은 후 에러가 발생하는 경우 순차적으로 각 에러 처리기가 해결 할 수 있으면 해결을 하고 할 수 없는 경우 다음으로 에러를 전달하는 방식

- 예외처리는 반드시 좁은 범위에서 넓은 범위로 확장해야 함

def divide(a, b):

    return a / b


try:

    c = divide(5, 'string')


except Exception:

    # 모든 에러에 대해서 이 부분에서 처리, 하위 에러 처리기는 어떠한 예외도 받지 못함  

    print("음~무슨 에러인지 모르겠어요!!")

except ZeroDivisionError:

    print("두 번째 인자는 0이면 안됩니다.")

except TypeError:

    print("모든 인수는 숫자이어야 합니다.")

음~무슨 에러인지 모르겠어요!!

4) else와 finally 예제

def divide(a, b):

    return a / b


try:

    c = divide(5, 2)


except ZeroDivisionError:

    print("두 번째 인자는 0이면 안됩니다.")

except TypeError:

    print("모든 인수는 숫자이어야 합니다.")

except:  

    print("ZeroDivisionError, TypeError를 제외한 다른 에러")

else:

    # 예외가 발생하지 않는 경우 

    print("Result: {0}".format(c))

finally:

    # 예외 발생 유무와 상관없이 수행 

    print("항상 finally 블록은 수행됩니다.")

Result: 2.5

항상 finally 블록은 수행됩니다.

5) 'as' 구문으로 예외 인스턴스 객체의 추가적인 정보를 출력하는 예제

def divide(a, b):

    return a / b


try:

    c = divide(5, "af")


except TypeError as e:

    # 전달되는 예외 인스턴스 객체를 e로 받아서 사용 

    print("에러: ", e.args[0])

except Exception:  

    print("음~ 무슨 에러인지 모르겠어요!!")

에러:  unsupported operand type(s) for /: 'int' and 'str'

6) 에러를 묶어서 처리하는 예제

- 에러의 종류는 틀리지만 예외 처리하는 부분은 동일한 경우

def divide(a, b):

    return a / b


try:

    c = divide(5, 0)


except (ZeroDivisionError, OverflowError, FloatingPointError):

    print("수치 연산 관련 에러입니다.")

except TypeError:

    print("모든 인수는 숫자이어야 합니다.")

except Exception:

    print("음~ 무슨 에러인지 모르겠어요!!")

수치 연산 관련 에러입니다.

7) 상위 에러를 처리하여 하위 모든 에러를 처리하는 예제

- 예외 클래스 계층 구조에서 부모 클래스를 except 구문으로 에러를 처리하면 부모 클래스를 상속 받은 하위 모든 클래스도 동일한 에러 처리를 함

      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError

def divide(a, b):

    return a / b


try:

    c = divide(5, 0)

    

except ArithmeticError:

    # 상위 클래스를 처리시 하위 모든 클래스도 이 부분에서 처리 

    print("수치 연산 관련 에러입니다.")

except TypeError:

    print("모든 인수는 숫자이어야 합니다.")

except Exception:

    print("음~무슨 에러인지 모르겠어요!!")


수치 연산 관련 에러입니다.

8) try-finally 구문 예제

- try-finally 구조의 경우 finally 블록 생략 불가능

- test.txt

Test!!!

try:

    print('#1 try')

    f = open(FilePath, 'r')

    

    try:

        print('#2 try')

        data = f.read(128)

        print(data)

    finally:

        print('#2 finally')

        f.close()


except IOError:

    print("Fail to open {0} file".format(FilePath))

a.  file을 성공적으로 open 했을 경우

#1 try

#2 try

Test!!!

#2 finally

b. file open에 실패한 경우

#1 try

Fail to open ./test1.txt file


raise 구문

- 의도적으로 예외를 발생시켜야 하는 경우 사용

raise [Exception] <- 해당 예외를 발생 시킴

raise [Exception(data)] <- 예외를 발생시 관련 데이터를 전달함

raise <- 발생된 예외를 상위로 전달

- raise 구문의 예외로 올수 있는 것: 내장 예외, 사용자 정의 예외

- 사용자 정의 예외를 생성하는 경우, 반드시 내장 클래스인 Exception을 상속 받아서 정의 해야함


1. 내장 예외 발생

def RaiseErrorFunc():

    raise NameError


try:

    RaiseErrorFunc()

except:

    print("NameError is Catched")

NameError is Catched


2. 내장 예외 전달 예제

- 예외를 상위로 전달하는 예제

- 예외가 발생할 때의 콜스택 정보와 raise구문에서 전달한 인자를 확인 가능

def RaiseErrorFunc():

    raise NameError("NameError의 인자")


def PropagateError():

    try:

        RaiseErrorFunc()

    except:

        print("에러전달 이전에 먼저 이 메시지가 출력됩니다.")

        # 발생한 에러를 상위로 전달

        raise


PropagateError()


에러전달 이전에 먼저 이 메시지가 출력됩니다.

    PropagateError()

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 162, in PropagateError

    RaiseErrorFunc()

  File "/Users/eunguru/Source/Python/Exception/src/Exception.py", line 158, in RaiseErrorFunc

    raise NameError("NameError의 인자")

NameError: NameError의 인자


사용자 정의 예외

- 모든 사용자 정의 예외는 내장예외인 Exception 클래스나 그 하위 클래스를 상속 받아 구현 되어야 함

- 전달 되어야 하는 인자가 있는 경우 생성자에서 클래스 멤버 변수를 이용하여 저장 가능

- 정의된 클래스는 개발자가 원하는 경우 raise 구문으로 예외 발생 가능

# 사용자 정의 예외 정의 

class NegativeDivisionError(Exception):

    def __init__(self, value):

        self.value = value

    

def PositiveDivide(a, b):

    if(b < 0):

        # 제수가 0보다 작은 경우, NegativeDivisionError 발생 

        raise NegativeDivisionError(b)

    return a / b

    

try:

    ret = PositiveDivide(10, -3)

    print("10 / 3 = {0}".format(ret))

except NegativeDivisionError as e:

    # 사용자 정의 예외인 경우 

    print("Error - second argument of PositiveDivide is", e.value)

except ZeroDivisionError as e:

    # 0으로 나누는 경우 

    print("Error -", e.args[0])

except:

    # 그 외 모든 예외의 경우 

    print(e.args)

Error - second argument of PositiveDivide is -3


assert 구문

- assert: 예외를 발생 시키는 방법

- 일반적으로 개발과정에서 제약 사항을 설정한 목적으로 사용, 인자로 받은 조건식이 거짓인 경우 AssertionError가 발생

assert_stmt ::=  "assert" expression ["," expression]
if __debug__:
   if not expression: raise AssertionError
if __debug__:
   if not expression1: raise AssertionError(expression2)

- __debug__ 변수를 설정하기 위해 명령 프롬프트에서 파이썬 코드를 실행할 때, 최적화 옵션을 설정하면 __debug__의 값은 False가 됨

- eclipse + pydev에서 설정하는 방법은 찾아보겠음..

'컴&프로그래밍 > Python' 카테고리의 다른 글

14. 데이터베이스 사용  (0) 2015.08.03
13. 파일시스템  (0) 2015.07.02
9. C/C++와 연동  (3) 2015.03.14
8. 입출력  (0) 2015.01.14
6. 모듈  (0) 2014.12.29
Mac OS X Yosemite에서 PyCharm 설치 후 실행  (0) 2014.12.27
5. 클래스  (0) 2014.12.20
4. 제어  (0) 2014.12.19
Google Python Tutorial - Basic Python Exercises #2 List  (0) 2014.12.11