파이썬 예외처리(Exception)

윤태영·2023년 11월 21일
0
post-thumbnail

이미지 출처: https://wikidocs.net/192339

예외는 프로그램의 로직에서 발생합니다. 직접 작성한 코드에서 어떤 예외가 발생해서 내가 생각한 의도대로 프로그램이 작동하지 않는 것을 말한다. 엄밀히 말하면 예외와 에러는 다릅니다. 예외는 작성한 코드에서 비정상적으로 방생하는 이벤트라고 보시면 됩니다. 예측이 가능한 예외가 있고 불가능한 예외가 있다. 만약 어떤 웹사이트에서 올바른 아이디와 비밀번호를 가지고 로그인을 시도하려고 하는데 로그인이되지않늗것들은 예측가능한 예외라고 볼 수 있습니다. 하드디스크 용량 부족의 경우는 예측 불가능한 예외입니다. 에러는 예외와 다르게 우리의 어떤 운영환경에서 발생합니다.

에러는 뭐고 예외는 이것 이렇게 외우지 말고, 어찌됐든 중간에 잘못된 값을 방생시키거나 의도한 대로 동작하지 않으면 예외로 봅시다. 예외의 종류, Python에서 나타날 수 있는 예외의 종류 등을 오늘 알아보겠습니다.😄

예외(Exception)개념 및 처리

  • 예외 종류
  • 다양한 예외 재연
  • 예외 처리 기본
  • 예외 처리 패턴
  • 예외 처리 실습

예외 종류

  • SyntaxError(문법이 틀렸을 경우에 나오는 에러)
  • TypeError(서로 더할 수 없는 자료형을 더했을때)
  • NameError(없는 변수를 참조할때)
  • indexError,ValueError, KeyError

문법적으로는 예외가 없지만, 코드 실행 프로세스(단계)발생하는 예외도 중요

  1. 예외는 반드시 처리
  2. 로그(증거)는 반드시 남긴다.(에러가 발생했을 경우 로그를 본다.)
  3. 예외는 던져진다.(다른데로 처리 위임가능)
  4. 예외 무시

SyntaxError : 문법 오류 📕

# 따옴표를 붙이지 않음,괄호를 2개 사용등과같은 SyntaxError
print('error)
>>> SyntaxError: unterminated string literal (detected at line 1)
print('error'))
>>> SyntaxError: unmatched ')'
ir True:
	pass
>>> SyntaxError: invalid syntax

NameError : 참조 없음 📕

참조가 없는 c를 출력하면 NameError 발생
a = 10
b = 15
print(c)
>>> NameError: name 'c' is not defined

ZeroDivsionError 📕

# 네이밍 그대로 100을 0으로 나눌 수 없을 때 ZeroDivsionError 발생
print(100/0) 
>>> ZeroDivisionError: division by zero

IndexError 📕

# 리스트의 5번째 인덱스에 접근하면 범위를 벗어났다는 오류가 발생합니다. for 문을 사용 시 발생할 수 있습니다.
x = [50, 70, 90]
print(x[1])
print(x[4])
>>> IndexError: list index out of 
# 리스트의 마지막 요소부터 빼는데 4번째부터는 빈리스트이기에 IndexError 발생
print(x.pop())
print(x.pop())
print(x.pop())
print(x.pop())
>>> IndexError: pop from empty list

KeyError 📕

KeyError는 주로 딕셔너리에서 나오는 에러로 'hobby'를 가지고 있는 key가 존재하지 않기에 발생
dic = {'name': 'Lee', 'Age': 41, 'City': 'Busan'}
print(dic['hobby'])
>>> KeyError: 'hobby'
# 예전에 배웠듯이 get method는 예외 발생x
print(dic.get('hobby')) 

완벽한 프로그램을 만드는 것은 불가능하기에 에러가 발생하면 수정하고 또 발생하면 수정하고를 반복하여 예외 처리를 권장합니다.

예외 없는 것을 가정하고 프로그램 작성 -> 런타임 예외 발생 시 예외 처리 권장(EAFP)

AttributeError : 모듈, 클래스에 있는 잘못된 속성 사용 예외 KeyError 📕

파이썬 내부적으로 있는 time 모듈에서는 time2라는 메소드가 없기 때문에 속성에 Attribute가 없다.

import time
print(time.time2())
>>> AttributeError: module 'time' has no attribute 'time2'

ValueError 📕

어떤 자료구조 안에서, 시퀀스형 자료 안에서 어떤 데이터를 참조할때 존재하지 않는경우 발생

x = [10, 50, 90]
x.remove(50)
print(x)
>>> [10, 90]
x.remove(200)
>>> ValueError: list.remove(x): x not in list

FileNotFoundError 📕

현재 여기 위치에는 test.txt라는 파일이 없기에 오류 발생

# open함수로 txt파일이나 텍스트 파일을 가져올 수 있습니다.
f = open('test.txt') 
>>> FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'

TypeError 📕

자료형에 맞지 않는 연산을 수행 할 경우 발생

  • 튜플은 불변형이기에, 내부적 구조로 데이터를 하나로 합칠수 없다.
x = [1,2]
y = (1,2)
z = 'test'
print(x + y) 
>>> TypeError: can only concatenate list (not "tuple") to list
print(x + z)
>>> TypeError: can only concatenate list (not "str") to list
print(y + z)
>>> TypeError: can only concatenate tuple (not "str") to tuple

튜플을 리스트로 형변환 하면 더해진다.

print(x + list(y))
>> [1, 2, 1, 2]
print(x + list(z))
>>> [1, 2, 't', 'e', 's', 't']

예외 처리 기본 📕

try : 에러가 발생 할 가능성이 있는 코드 실행
except 에러명1 : 여러개 가능 , 예를들어 TypeError가 발생하면 except로 잡는다는 것
except 에러명2 :
else : try 불록의 에러가 없을 경우 실행 , try문에서 에러가 발생하지 않으면 else문 실행
finally : 항상 실행

예1)

try문 아래에서 예외가 발생할 가능성이 있는 어떤 파일을 처리하거나 데이터베이스를 연동하거나 또는 다른 사이트 접속해서 크롤링을 할경우 이런 코드들을 try문에 넣어야 한다. 나의 코드는 정확해도 내가 방문하고자 하는 사이트가 서버 문제가 있을 수도 있고, 접속하고자 하는 프로그램들이 외부 어떤 커넥션을 연결할 때 에러가 생길 수 있기 때문이다.

  • 예외가 발생했을때는 else문이 실행되지 않고, 정상적일때는 else문 실행
  • try문 사이에는 외부적으로 예외가 발생할것같은 상황이 예측이 될때 try문을 감싸면 좋다.
name = ['Kim', 'Lee', 'Park']
try :
    z = 'Kim' 
    x = name.index(z)
    print('{} Found it! {} in name'.format(z, x+1))
# 만약 name리스트에 'Kim'이라는 값이 없으면 ValueError가 발생하겠죠!
except ValueError:
    print('Not Found it! - Occurred ValueError!')
else:
    print('Ok! else.')
>>> Kim Found it! 1 in name
>>> Ok! else.

예2)

name = ['Kim', 'Lee', 'Park']
try:
    z = 'Kim'    
    x = name.index(z)
    print('{} Found it! {} in name'.format(z, x+1))
except :#Exception:  # 모든 에러를 잡을 수 있지만, 어떤 에러가 발생했는지를 정확하게 알 수가 없고, 일단 예외라고 알 수 있다.
    print('Not found it! = Occurred ValueError!')
else:
    print('Ok else.')
>>> Kim Found it! 1 in name
>>> Ok else.

예3)

만약 리스트에 없는 값을 찾으면 어떻게 코드가 실행 될까요?
except Exception은 모든 에러, 예외를 어떤 모든 예외 클래스의 부격이라서 이 부모가 그냥 에러를 잡는것

name = ['Kim', 'Lee', 'Park']
try:
    z = 'Cho'    
    x = name.index(z)
    print('{} Found it! {} in name'.format(z, x+1))
except Exception as e:
    print('Not found it! = Occurred ValueError!')
else: # else문은 예외가 발생하지 않아야 실행 되는것
    print('Ok else.')
>>> Not found it! = Occurred ValueError!

에러의 내용을 알 수 있다.

try:
    z = 'Cho'    
    x = name.index(z)
    print('{} Found it! {} in name'.format(z, x+1))
except Exception as e:
    print(e) # 에러의 내용을 알수 있다.
    print('Not found it! = Occurred ValueError!')
else: # else문은 예외가 발생하지 않아야 실행 되는것
    print('Ok else.')
finally:
    print('Ok! finally!') # finally는 예외가 발생해도 무조건 실행
>>> 'Cho' is not in list
>>> Not found it! = Occurred ValueError!
>>> Ok! finally!

예4)

예외를 일부로 발생시킨 예제

  • raise 키워드로 예외 직접 발생
  • raise는 예외를 직접 발생시키는 키워드이기에 프로그램의 설계상 들어오면 안되는 값이 들어오거나,파이썬의 어떤 문법의 원칙에 입각한 예는 아니지만 직접설계한 예외이기에 아래처럼 예외로써도 간주가능

우리가 사이트를 운영한다고 가정해 보자. 관리자인 a = 'youn'인 사람이 로그인하면 'Ok Pass!'가 실행되면서 로그인될 것이고 아닌 경우에는 로그인이 되지 않겠죠. 이것은 파이썬의 문법 에러가 아닌 우리 회사의 정책이라고 볼 수 있습니다. 그래서 논리적인 룰에 의해서 에러를 발생시킵니다.

  • a가 Kim이 아닌경우 무조건 error를 발생
name = ['Kim', 'Lee', 'Park']
try:
    a = 'Park'
    if a == 'Youn':
        print('OK! Pass!')
    else: # 논리적인 룰에의해서 발생으로 youn이 아니면 무조건 ValuError를 발생하자, 근데 우리가 배웠던 ValueError는 index에 진짜값이 없거나 파이썬에서 자동으로 발생하는것으로 값이 있으면 에러가발생하지 않는다.
        raise ValueError  # 즉 if문에서 a가 youn이 아니라고해서  ValueError를 발생시킬 이유가없지만 우리가 raise로 직접 발생시킨것, 이렇게 발생시켜서 에러를 잡으면, 운영하는 관리자가'youn'이 안들어온것을 알고 논리적으로 프로그램이 설계한 원칙대로 설계를 알 수 있다.
except ValueError:
    print('Occurred ! Exception')
else:
    print('Ok else!')
>>> Occurred ! Exception

오늘은 예외 종류, 예외 처리의 다양한 패턴을 알아보았습니다. 주로 예4를 많이 사용하기에 연습하시면 좋을 것 같습니다. 😄🧐

출처 : 인프런

profile
ice blue

0개의 댓글