A Byte of Python - Exceptions Python


Exceptions

익셉션은 파일을 열려는데 파일이 없는 상황과 같이 프로그램에서 예외적인 상황을 처리하기 위한 것이다. 

파이썬은 발생을 보고하고 에러가 있음을 알린다

에러

단순 print 함수 호출을 했다. print를 Print라고 쓰면 어떻게 될까? 이 경우 파이썬은 문법 에러를 발생시킨다

>>> Print("Hello World")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Print' is not defined
>>> print("Hello World")
Hello World

NameError가 발생하고 감지한 위치도 보여준다. 이 것이 이 에러에 대한 에러핸들러가 하는 것이다.

익셉션

사용자로 부터 입력 읽기를 시도할 것이다. 한 라인을 입력하고 엔터키를 누른다. 컴퓨터가 입력을 받는데 [ctrl-d] 를 누르면 어떻게 될까. 

>>> s = input('Error something --> ')
Enter something --> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
EOFError

Python raises an error called EOFError which basically means it found an end of file symbol (which is represented by ctrl-d) when it did not expect to see it.

예외 다루기

try..except 문으로 예외를 다룰 수 있다. 원 문장을 try 블럭 내에 두고 except 블럭에 에러 핸들러를 둔다.

exceptions_handle.py
try:
  text = input('Enter something --> ')
except EOFError:
  print('Why did you do an EOF on me?')
except KeyboardInterrupt:
  print('You cancelled the operation.')
else:
  print('You entered {}'.format(text))

Output:

# Press ctrl + d$ python exceptions_handle.pyEnter something --> Why did you do an EOF on me?# Press ctrl + c$ python exceptions_handle.pyEnter something --> ^CYou cancelled the operation.$ python exceptions_handle.pyEnter something --> No exceptionsYou entered No exceptions

동작분석

예외/에러가 발생할 수 있는 모든 문장을 try 블럭에 넣고 except 블럭에서 대상 에러/예외를 처리하는 핸들러를 넣는다. except는 특정 에러나 예외를 다루는데 에러/예외의 괄호로된 리스트로 여러개를 담을 수도 있다. 에러나 예외의 이름이 지정도지 않으면 모든 에러와 예외를 다루게 될 것이다.

모든 try문은 최소 하나의 except 문을 가져야 한다. 

만약 특정 에러나 예외가 다뤄지지 않으면 파이썬 기본 핸들러가 호출되는데 프로그램을 중지하고 에러메시지를 출력한다. 이는 위에서 살펴본바 있다.

try..except 블럭과 함께 else문을 쓸수도 있다. else문은 예외가 발생하지 않은 상황을 의미한다.

다음 예시에서 어떻게 예외 객체를 가져오는지 그래서 추가정보를 얻어오도록 처리한다.

예외 발생하기

raise문과 함께 에러/예외의 이름그리고 던져질 예외 객체를 사용해 예외를 발생시킬 수 있다.
발생시키는 에러 또는 예외는 클래스로서 직접적으로 또는 간접적으로 Exception 클래스에서 파생되어야 한다.

exceptions_raise.py

class ShortInputException(Exception):
  '''A user-defined exception class.'''
  def __init__(self, length, atleast):
    Exception.__init__(self)
    self.length = length
    self.atleast = atleast

try:
  text=input("Enter something --> ")
  if len(text) < 3:
    raise ShortInputException(len(text),3)
except EOFError:
  print("Why did you do an EOF on me?")
except ShortInputException as ex:
  print(("ShortInputException: The input was {} long, expected at least {}').format(ex.length, ex.atleast))
else:
  print("No exception was raised.")

Output:

$ python exceptions_raise.pyEnter something --> aShortInputException: The input was 1 long, expected at least 3$ python exceptions_raise.pyEnter something --> abcNo exception was raised.

동작 방식

새로운 예외형식인 ShortInputException을 생성했다. 필드가 2개가 있는데 지금 입력으로 건내어진 길이 length와 입력되어야 할 최소길이를 나타내는 atleast이다. 

except문에서 에러의 클래스를 as로 변수명에 에러/예외 객체를 저장했다. 이는 함수호출에서의 매개변수와 유사하다. 이 특정 except 문 내에서 length, atleast필드를 사용해 사용자에게 세부적인 메시지로 만든다.

Try .. Finally

프로그램에서 파일을 읽는다고 가정하자. 파일 객체가 적절히 닫아질지, 예외가 발생하지 않을지 어떻게 확정할까? 이는 finally 블럭을 사용해 수행될 수 있다.

exceptions_finally.py

import sys
import time

f = None
try:
  f = open("poem.txt")
  while True:
    line = f.readline()
    if len(line) == 0:
      break
    print(line, end='')
    sys.stdout.flush()
    print("Press ctrl+c now")
    time.sleep(2)
except IOError:
  print("Could not find file poem.txt")
except KeyboardInterrupt:
  print("!! You cancelled the reading from the file.")
finally:
  if f:
    f.close()
  print("(Cleaning up: Closed the file)")

Output:

$ python exceptions_finally.pyProgramming is funPress ctrl+c now^C!! You cancelled the reading from the file.(Cleaning up: Closed the file)

동작 방식

보통의 파일읽기였지만 한 라인당 time.sleep함수를 사용해 2초간 슬립했다. 프로그램이 실행중일때 ctrl+c 를 눌러 중지/취소 시킨다.

KeyboardInterrup 예외가 발생하면 프로그램이 종료된다. 하지만 그 전에 finally 절이 실행되어 파일이 항상 닫아지게 한다.

값은 0또는 None으로 할당되었거나 시퀀스 또는 콜렉션이 빈 것이면 파이썬에 의해 False로 간주한다. 이 것이 위의 if f: 로 쓸수있는 이유이다.

sys.stdout.flush() 를 스크린에 즉시 보여지도록 print이후에 바로 쓴다

with 문

try 블록내의 리소스를 받고 finally 블록에서 리소스를 릴리즈하는 것은 공통된 패턴이다. with 문을 통해 이를 더욱 깔끔하게 처리할 수 있다.

exceptions_using_with.py:
with open("poem.txt") as f:
  for line in f:
    print(line, end='')

동작방식

출력은 이전 예시와 동일하다. 이 곳의 차이치점은 open 함수를 with문과 함께 사용했다는 점이다. with open을 통해 자동적으로 파일을 닫게 한다.

with 문을 통해 사용되는 프로토콜이 있다. 이 것은 open 문으로 반환되는 객체를 페치하고 이 경우 "thefile" 이라고 부르자.

이는 thefile.__enter__ 함수를 코드의 블록 시작저네 호출한다. 그리고 항상 코드 블록의 끝에서 thefile.__exit__ 를 호출한다.

__exit__ 메소드로 자동적으로 finally 블록이 실행된다. 이 것은 try.. finally문을 명시적으로 계속 사용할필요가 없게 해준다.

이 부분에 대한 더 많은 포괄적 사항은 PEP 343을 살펴본다.

갈무리

try .. except 와 try .. finally 문을 사용하는 법을 살펴봤다. 어떻게 예외형식을 만드는지 어떻게 예외를 발생시키는지도 봤다.

다음은 파이썬 표준 라이브러리이다.






덧글

댓글 입력 영역