티스토리 뷰

AI/Python

[python] 예외처리, 파일 다루기

brave_sol 2024. 6. 18. 16:14

[1] 예외처리  Exception Handling

(1) 예외 Exception 

1) 예상 가능한 예외

- 발생 여부를 사전에 인지할 수 있는 예외

- 사용자의 잘못된 입력, 파일 호출 시 파일 없음

- 개발자가 반드시 명시적(if문, try~except문)으로 정의해야함

 

2) 예상 불

가능한 예외

- 인터프리터 과정에서 발생하는 예외, 개발자 실수

- 리스트의 범위를 넘어가는 값 호출, 정수 0으로 나눔

- 수행 불가시 인터프리터가 자동 호출

 

3) 예외 발생 시 후속조치

- 없는 파일 호출 → 파일 없음을 알림

- 게임 이상 종료 → 게임 정보 저장

 

(2) try ~ except 문법 : if문은 로직적인 문제, excpetion은 잘못된것(파일이 비었을때 등)을 처리할때 사용

try: 항상 실행되고, 예외를 감지, else: 예외가 없는 경우에만 실행

사용법 예시
try : 
  예외 발생 가능 코드
except < Exception Type >:
  예외 발생시 대응 코드
a= [1,2,3]
for i in range(5):
  try:
    print(i, 10/i)
    print(a[i])
    print(v)
  except ZeroDivisionError:
    print("Not divided by 0")
  except IndexError as e:
    print(e)
  except Exception as e:
    print(e)

# 출력결과
Not divided by 0
1 10.0
2
name 'v' is not defined
2 5.0
3
name 'v' is not defined
3 3.3333333333333335
list index out of range
4 2.5
list index out of range
try : 
  예외 발생 가능 코드
except < Exception Type >:
  예외 발생시 대응 코드
else:
  예외가 발생하지 않을때 동작 
보기 복잡해서 비추
try : 
  예외 발생 가능 코드
except < Exception Type >:
  예외 발생시 대응 코드
finally:
  예외가 발생여부와 상관X 항상 실행
보기 복잡해서 비추

 

(3) Built-in Exception : 기본적으로 제공하는 예외(https://docs.python.org/3/library/exceptions.html)

Exception 이름 내용
IndexError List의 Index 범위를 넘어갈 떄
NameError 존재하지 않은 변수를 호출 할 떄
ZeroDivisionError 0으로 숫자를 나눌 때
ValueError 변환할 수 없는 문자/숫자를 변환할 때
FileNotFoundError 존재하지 않는 파일을 호출할 때
Exception 특별히 지정하지 않아도 자동으로 예외 잡아줌(valueError같은거)
*but 권장하지 않음, Exception이 어디서 발생한지 알기 어려워서

 

(4) raise : 필요에 따라 강제로 Excpetion 발생하여 프로그램 종료시킴(시간, 리소스 낭비 방지)

- 잘못 사용할 때 프로그램을 종료시킬 필요가 있을 때

사용법 예시
raise <Exception Type> (예외정보) while True:
  value = input("변환할 정수 값을 입력해주세요")
  for digit in value:
    if digit not in "0123456789":
      raise ValueError("숫자값을 입력하지 않으셨습니다.")
    print("정수값으로 변환된 숫자 :", int(value))


# d 입력시 "ValueError: 숫자값을 입력하지 않으셨습니다." 발생

 

(5) assert 구문

사용법 예시
assert 예외조건 def get_binary_number(decimal_number):
  assert isinstance(decimal_number, int)
  return bin(decimal_number)

print(get_binary_number(10)) # 0b1010
print(get_binary_number(10.0)) # 에러발생, 프로그램 중지, "AssertionError"

 

[2] 파일처리 (File handling)

(1) 파일 시스템 (File system)

- OS에서 파일을 저장하는 트리구조 저장 체계

(2) 파일: 컴퓨터 등의 기기에서 의미 있는 정보를 담는 논리적인 단위. 

- 모든 프로그램은 파일로 구성되어 있고, 파일을 사용한다.

- 종류 : text 파일, binary 파일

- 컴퓨터는 text 파일을 처리하기 위해 binary 파일로 변환시킴(예: pyc파일)

- 모든 text파일도 실제는 binary파일 (ASCII/Unicode 문자열 집합으로 저장되어 사람이 읽을 수 있음)

Binary 파일 Text 파일
- 컴퓨터만 이해할 수 있는 형태인 이진(법)형식으로 저장된 파일
- 일반적으로 메모장으로 열면 내용이 깨져 보임(메모장 해설 불가)
- 엑셀파일, 워드파일 등등
- 인간도 이해할 수 있는 형태인 무자열 형식으로 저장된 파일
- 메모장으로 열리면 text 파일
- 메모장에 저장된 파일, HTML파일, 파이썬 코드파일 등

 

(3) 파일처리

- 파이썬은 파일 처리를 위해 "open" 키워드를 사용함

사용법 app.py  i_have_a_dream.txt
(1) open / close
f = open("<파일이름>", "접근 모드")
# 대상 파일이 같은 폴더에 있어야 함
# 파일을 읽어 올 수 있도록 지정하는 것임
f.close()
f = open("i_have_a_drea.txt", "r")
contents = f.read()
print(contents)
f.close

# 출력결과
this is test
for read()


this is test
for read()
this is test
for read()
(2) with 구문 
with 아래 들여쓰기 되어 있는 구문이 일어나는 동안 실행
  구문
(f.close 쓰지 않아도 됨)
with open("i_have_a_dream.txt", "r") as my_file:
  contents = my_file.read()
  print(type(contents), contents)

# 출력결과
<class 'str'> this is test</class 'str'>
for read()

 

- 접근모드

파일열기모드 설명
r (읽기모드) 파일을 읽기만 할 때 사용
w (쓰기모드) 파일에 내용을 쓸 때 사용
a (추가모드) 파일의 마지막에 새로운 내용을 추가 시킬 때 사용

 

(4) read

구분 예시
- read() : 파일 읽어와서 문자열로 반환 with open("i_have_a_dream.txt", "r") as my_file:
  contents = my_file.read()
  print(type(contents))
  print(contents)

#출력결과
<class 'str'>
this is test
for read()
- readlines() : 파일 내용 한줄씩 list로 반환
* 실행하자마자 모든 라인을 메모리에 올림
with open("i_have_a_dream.txt", "r") as my_file:
  contents_list = my_file.readlines()
  print(type(contents_list))
  print(contents_list)

# 출력결과
<class 'list'>
['this is test\n', 'for read()']
- readline() : 실행시 마다 한 줄 씩 읽어오기
* 용량이 너무 커서 한번에 메모리에 다 올릴 수 없을때
with open("i_have_a_dream.txt", "r") as my_file:
  i = 0
  while True:
    line = my_file.readline()
    if not line:
      break
    print(str(i)+ "===" + line.replace("\n","")) # 한줄씩 값 출력
    i = i+1

# 출력결과
0===this is test
1===for read()

 

(5) write (w: 파일생성, a: 내용추가)

- encoding : 리눅스와 맥은 한글 utf8쓰는데, 윈도우는 cp949 포맷을 사용하므로 협업을 위해 utf8로 바꿔줘야함

구분 app.py count_log.txt
 - "w"
파일생성
f = open("count_log.txt","w"encoding = "utf8")
for i in range(1,6):
  data = "%d번째 줄입니다. \n" % i
  f.write(data)
f.close
1번째 줄입니다. 
2번째 줄입니다. 
3번째 줄입니다. 
4번째 줄입니다. 
5번째 줄입니다. 
- "a"
추가하기
f = open("count_log.txt","a"encoding = "utf8")
for i in range(0,4):
  data = "%d번째 줄입니다. \n" % i
  f.write(data)
f.close
1번째 줄입니다. 
2번째 줄입니다. 
3번째 줄입니다. 
4번째 줄입니다. 
5번째 줄입니다. 
0번째 줄입니다. 
1번째 줄입니다. 
2번째 줄입니다. 
3번째 줄입니다. 

 

(6) directory 다루기

구분
OS 모듈 사용
 - 디렉토리가 있는지 확인하기
import os
os.mkdir("log") # 코드 실행 시 log 폴더 생성됨

(1) FileExistsError 이용

import os

try:
  os.mkdir("log")
except FileExistsError as e:
  print("Already created")

# 위에서 log 폴더 만들었기 때문에 Already created

(2) os.path.exists 이용
print(os.path.exists("log")) # True
shutil 모듈 사용
- 파일 복사
import os
import shutil

source = "i_have_a_dream.txt"
dest = os.path.join("abc","copy.txt")
print(dest) # abc\copy.txt
# join 으로 상대 경로 생성 copy는 새로 만들 파일명

shutil.copy(source, dest)
# shutil.copy : 파일 복사
# "abc"폴더 밑에 copy.txt 파일 생성됨(파일 내용은 i_have_a_dream.txt와 같음)
pathlib 모듈 사용
* path를 객체로 다룸
=> 윈도우/리눅스마다 path가 다른데 통일 가능
** 최근에 많이 사용
import pathlib

cwd = pathlib.Path.cwd()
print(cwd) # 현재 폴더 경로
print(cwd.parent) # 현재 폴더 상위 폴더 경로(부모 폴더 경로)
print(cwd.parent.parent) # 현재 폴더 상위 상위 폴더 경로 
print(list(cwd.parents)) # [현재 폴더 부모 폴더 경로, 그위, 그위, C드라이브까지 리스트로 나옴]
pickle
- 파이썬의 객체를 영속화(persistence)하는 built-in 객체
- 데이터, object 등 실행중 정보를 저장하고 불러와서 사용
- 저장해야하는 정보, 계산 결과(모델)등 활용이 많음

* pickle은 파이썬에 특화된 binary 파일임 => 메모장에서 안열림
* 객체는 원래 메모리에 있어야함 => 메모리는 파이썬 인터프리터가 끝나면 지워짐
저장해서 나중에 불러와서 사용하고 싶을때 : pickle

import pickle

f = open("list.pickle","wb") # wb : write binary, 현재 폴더에 list.pickle파일생성됨
test = [1,2,3,4,5]
pickle.dump(test, f) # test를 f에 저장해라
f.close()

del test
print(test) # test삭제되서 에러남

f = open("list.pickle", "rb") # rb : read binary 읽어옴
test_pickle = pickle.load(f)
print(test_pickle)
f.close

# 출력결과 : [1, 2, 3, 4, 5]
# test를 지워도 pickle로 저장시켜놨기 때문에 test에 담았던 값 불러와 사용 가능

 

[3] 로그 다루기: Logging Handling

- 프로그램이 실행되는 동안 일어나는 정보 기록 남기기

- 유저의 접근, 프로그램의 Exception, 특정 함수의 사용

- Console 화면에 출력(분석 시 사용불가), 파일에 남기기, DB에 남기기 등등

- 기록된 로그를 분석하여 의미있는 결과를 도출 할 수 있음

- 실행시점에서 남겨야 하는 기록(유저분석 위해), 개발시점에서 남겨야 하는 기록(에러 등 사전에 잡기 위해, 디버깅)

- 레벨별(개발시, 운영시), 모듈별 기록을 남길 필요도 있음

- 개발시점 ( debug ) > 운영시점( info ) > 사용자 ( warning > error > critical )

 

(1) 사용법

모듈 app.py  my.log
logging
* print문이랑 비슷
import logging

logger = logging.getLogger("main") 
stream_handler = logging.FileHandler(
  "my.log", mode = "a", encoding = "utf8"
)
logger.addHandler(stream_handler) 
#my.log 파일에 로그를 기록하겠다
# a는 append의 약자, w 는 새로 생성

logging.basicConfig(level=logging.DEBUG) 
# 선언 안해주면 warning이 기본값
logger.setLevel(logging.INFO) # 레벨설정
logger.debug("틀렸잖아!")
logger.info("확인해")
logger.warning("조심해!")
logger.error("에러났어!!")
logger.critical("망했다..")


#출력결과
INFO:main:확인해
WARNING:main:조심해!
ERROR:main:에러났어!!
CRITICAL:main:망했다..
확인해
조심해!
에러났어!!
망했다..

 

(2) 로깅 레벨(logging level)

레벨 개요 예시
debug 개발시 처리 기록을 남겨야하는 로그 정보를 남김 - 다음 함수로 A를 호출함
- 변수 A를 무엇으로 변경함
info 처리가 진행되는 동안의 정보를 알림 - 서버가 시작되었음
- 서버가 종료됨
- 사용자 A가 프로그램에 접속함
warning 사용자가 잘못 입력한 정보나 처리는 가능하나 원래 개발시 의도치 않는 정보가 들어왔을 때 알림 - str 입력을 기대했으나, int가 입력됨 → str casting으로 처리
- 함수에  argument로 이차원 리스트를 기대했으나 일차원리스트가 들어옴 이차원으로 변환 후 처리
error 잘못된 처리로 인해 에러가 났으나, 프로그램은 동작할 수 있음을 알림 - 파일에 기록을 해야하는데 파일이 없음 예외처리 후 사용자에게 알림
- 외부서비스와 연결 불가
critical 잘못된 처리로 데이터 손실이나 더이상 프로그램이 동작할 수 없음을 알림 - 잘못된 접근으로 해당 파일이 삭제됨
- 사용자에 의한 강제 종료

 

(3) 로그파일, 레벨 등 사전에 설정 : 데이터 파일 위치, 파일 저장 장소, Operation Type 등

설정방법 app.py example.cfg
(1) configparser : 파일에 저장

- 프로그램의 실행 설정을 file에 저장
- section, key, value 값의 형태로 설정된 설정 파일을 사용
- 설정 파일을 dict type으로 호출 후 사용
import configparser

config = configparser.ConfigParser()

config.read('example.cfg')
print(config.sections())

print(config['SectionThree'])
for key in config['SectionOne']:
  value = config['SectionOne'][key]
  print("{0} : {1}".format(key, value))

# 출력결과
['SectionOne', 'SectionTwo', 'SectionThree']
<Section: SectionThree>
status : Single
name : Derek
value : Yes
age : 30
single : True
[SectionOne] # section - 대괄호
Status: Single
Name: Derek
Value: Yes
Age: 30
Single: True

[SectionTwo]
FavoriteColor = Green # :도 되고 =도 됨

[Section Three]
FamilyName: Johnson
(2) argparser : 실행시점에 저장
- Console창에서 프로그램 실행시 Setting 정보를 저장함
- 특수 모듈도 많이 존재하지만(TF), 일만적으로 argparse를 사용
- Command-Line Option 이라고 부름
import argparse

parser = argparse.ArgumentParser(description='Sum two integers.')
parser.add_argument('-a', "--a_value", dest = "a", help = "A integers", type = int, required = True)
parser.add_argument('-b', "--b_value", dest = "b", help = "B integers", type = int, required = True)

args = parser.parse_args()
print(args) # Namespace(a=10, b=20)
print(args.a) # 10
print(args.b) # 20
print(args.a+args.b) # 30

# python app.py -
a 10 -b 20 실행
 


(4) Logging Formmater

- Log의 결과값의 format을 지정해줄 수 있음

formatter = logging.Formatter('%(asctime)s %(levelname)s % (process)d %(message)s')

# 출력결과
2018-01-18 22:47:04, 385 ERROR 4410 ERROR occurred

- Log config file

app.py logging.conf
import logging
import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger()
[loggers]
keys = root

[handlers] # 핸들러는 이걸 쓸거구요~
keys = consolehandler

[formatters]
keys = simpleFormatter

[logger_root]
level = DEBUG
handlers = consolehandler

[handler_consoleHandler]
class = StreamHandler
level = DEBUG
formatter = simpleFormatter
args = (sys.stdout,)

 

 

 

※ 출처 : 네이버 부스트코스 - 인공지능 기초 다지기(https://www.boostcourse.org/ai100)

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함