네이버 부스트캠프 AI Tech/Pre-course

4. File / Exception / Log Handling

중앙백 2021. 12. 5. 21:30

1. Exception Handling

 

* Exception

1) 예상 가능한 예외 ( if 문으로 처리 가능 )

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

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

    - 개발자가 반드시 명시적으로 정의 해야함

2) 예상 불가능한 예외

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

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

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

 * '프로그램 = 제품', 모든 잘못된 상황에 대처가 필요. -> Exception Handling

 

 - try ~ except 문법

try:
    # 예외 발생 가능 코드
except <Exception Type>:
    # 예외 발생시 대응하는 코드
for i in range(10):
    try:
        print(10/i)
    except ZeroDivisionError as e:
        print("Not divided by 0")
        print(e) # 예외 정보 표시하기

 

 - Built-in Exception : 기본적으로 제공하는 예외

IndexError List의 Index 범위를 넘어갈 때
NameError 존재하지 않은 변수를 호출 할 때
ZeroDivisionError 0으로 숫자를 나눌 때
ValueError 변환할 수 없는 문자/숫자를 변환할 때
FileNotFoundError 존재하지 않는 파일을 호출할 때

 

 - try ~ except ~ else (개인적으로 비추천하는 방식)

try:
    # 예외 발생 가능 코드
except <Exception Type>:
    # 예외 발생시 동작하는 코드
else:
    # 예외가 발생하지 않을 때 동작하는 코드
for i in range(10):
    try:
        result = 10 // i
    except ZeroDivisionError:
        print("Not divided by 0")
    else:
        print(10 // i)

 

 - try ~ except ~ finally

try:
    # 예외 발생 가능 코드
except <Exception Type>:
    # 예외 발생시 동작하는 코드
finally:
    # 예외 발생 여부와 상관없이 실행됨

 

* raise 구문 : 필요에 따라 강제로 Exception을 발생

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

 

* assert 구문 : 특정 조건에 만족하지 않을 경우 예외 발생

assert 예외조건
def get_binary_nmubmer(decimal_number):
    assert isinstance(decimal_number, int)    # True or False로 나올 수 있게 하고 False일때 에러발생
    return bin(decimal_number)
    
print(get_binary_nmubmer(10))
print(get_binary_nmubmer(10.0))     # error 발생

 

 

2. File Handling

 

* Overview

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

 - File from wiki : 컴퓨터 등 기기에서 의미 있는 정보를 담는 논리적인 단위.

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

 - 기본적인 파일 종류로는 text파일과 binary파일로 나눔.

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

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

 - Binary 파일: 컴퓨터만 이해할 수 있는 이진형식으로 저장된 파일. 메모장으로 열면 내용이 깨져보임. 엑셀, 워드 등등.

 - Text 파일: 인간도 이해할 수 있는 문자열 형식으로 저장된 파일. 메모장으로 열면 내용 확인 가능. 메모장, HTML, 파이썬 코드 파일 등등.

 

 

* Python File I/O

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

f = open("<파일이름>", "접근 모드")
f.close()

r : 읽기모드 - 파일을 읽기만 할 때 사용

w : 쓰기모드 - 파일에 내용을 쓸 때 사용

a : 추가모드 - 파일의 마지막에 새로운 내용을 추가 시킬 때 사용

 

* File Read

read() : txt 파일 안에 있는 내용을 문자열로 반환. 엄밀히는 파일을 읽어올 수 있게 주소를 지정.

f = open("i_have_a_dream.txt","r")    # 대상 파일이 같은 폴더에 있어야 함.
contents = f.read()
print(contents)
f.close()

 

with 구문과 함께 사용하기

with open("i_have_a_dream.txt", "r") as my_file:
    contents = my_file.read()
    print(type(contents), contents)

 

한 줄씩 읽어 List Type으로 반환함.

with open("i_have_a_dream.txt", "r") as my_file:
    contents_list = my_file.readlines()    # 파일 전체를 list로 반환
    print(type(contents_list))    # Type 확인
    print(contents_list)    # 리스트 값 출력

 

실행 시 마다 한 줄 씩 읽어 오기

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

 

 

* File Write

 - mode는 'w', encoding="utf8"

f = open("count_log.txt",'w', encoding="utf8")
for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    f.write(data)
f.close()

 

 - mode 'a'는 추가 모드

with open("count_log.txt", 'a', encoding="utf8") as f:
    for i in range(1, 11):
        data = "%d번째 줄입니다.\n" % i
        f.write(data)

 

* 파이썬의 directory 다루기

 - OS 모듈을 사용하여 Directory 다루기 (폴더 만들기) / Shutil도 공부해보자

import os
os.mkdir("log")

 - 디렉토리가 있는지 확인하기

import os
if not os.path.isdir("log"):
    os.mkdir("log")

 - 최근에는 pathlib 모듈을 사용하여 path를 객체로 다룸.

 

* Log 파일 생성하기

1) 디렉토리가 있는지, 2) 파일이 있는지 확인 후

import os
if not os.path.isdir("log"):
    os.mkdir("log")
if not os.path.exists("log/count_log.txt"):
    f = open("log/count_log.txt", 'w', encoding="utf8")
    f.write("기록이 시작됩니다\n")
    f.close()
    
with open("log/count_log.txt", 'a', encoding="utf8") as f:
    import random, datetime
    for i in range(1, 11):
        stamp = str(datetime.datetime.now())
        value = random.random() * 1000000
        log_line = stamp + "\t" + str(value) + "값이 생성되었습니다" + "\n"
        f.write(log_line)

 

* Pickle

 - 파이썬 객체를 영속화(persistence)하는 built-in 객체

 - 데이터, object 등 실행중 정보를 저장 -> 불러와서 사용

 - 저장해야하는 정보, 계산 결과(모델) 등 활용이 많음

import pickle
f = open("list.pickle", "wb")    # write, binary
test = [1, 2, 3, 4, 5]
pickle.dump(test,f)    # 저장
f.close()
import pickle
f = open("list.pickle", "rb")    # read binary
test_pickle = pickle.load(f)    # 불러오기
print(test_pickle)
f.close()

 

 

 

3. Logging Handling

 - 핵 유저들을 어떻게 처리하지? - 상황을 기록하는 것부터 시작 - 로그 남기기

 

* 로그 남기기 - Logging

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

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

 - Console 화면에 출력, 파일에 남기기, DB에 남기기 등등

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

 - 실행시점에서 남겨야 하는 기록, 개발시점에서 남겨야 하는 기록

 

* print vs logging

 - 기록을 print로 남기는 것도 가능

 - But, Console 창에만 남기는 기록은 분석시 사용불가

 - 때로는 레벨별(개발,운영)로 기록을 남길 필요도 있음

 - 모듈별로 별도의 logging을 남길필요도 있음

 - 이러한 기능을 체계적으로 지원하는 모듈이 필요함

 

* logging 모듈

import logging

logging.debug("틀렸잖아")
logging.info("확인해")
logging.warning("조심해")
logging.error("에러났어")
logging.critical("망했다.")

 logging level : 프로그램 진행 상황에 따라 다른 레벨의 로그를 출력

                     DEBUG > INFO > WARNING > ERROR > Critical

                     logging.basicConfig(level=logging.DEBUG) 이런 식으로 레벨 설정 가능. 기본은 warning

 

* 실제 파일을 사용할 땐 여러가지 미리 설정해줘야함 : 데이터 파일 위치, 파일 저장 장소, Operation Type 등

 -> 설정해줄 방법 : 1) configparser - 파일에.  2) argparser - 실행 시점에

 

* configparser

 - 프로그램의 실행 설정을 file에 저장함

 - Section, Key, Value 값의 형태로 설정된 설정 파일을 사용

 - 설정파일을 Dict Type으로 호출 후 사용

 

* argparser

 - Console 창에서 프로그램 실행시 Setting 정보를 저장함

 - 거의 모든 Console 기반 Pythong 프로그램 기본으로 제공

 - 특수 모듈도 많이 존재하지만(TF), 일반적으로 argparse를 사용

 - Command-Line Option이라고 부름