File / Exception / Log Handling

2022. 12. 27. 09:23BOOTCAMP/boostcamp AI Tech Pre-Course

[생각해 보기] 프로그램 사용할 때 일어나는 오류들

  • 주소를 입렵하지 않고, 배송 요청
  • 저장도 안 했는데, 컴퓨터 전원이 나감
  • 게임 아이템 샀는데, 게임에서 튕김

→예상치 못한 많은 일(예외)들이 생김

 

Exception

1) 예상 가능한 예외

  • 발생 여부를 사전에 인지할 수 있는 예외
  • 사용자의 잘못된 입력, 파일 호출 시 파일 없음
  • 개발자가 반드시 명시적으로 정의해야 함

2) 예상이 불가능한 예외

  • 인터프리터 과정에서 발생하는 예외, 개발자 실수
  • 리스트의 범위를 넘어가는 값 호출, 정수 0으로 나눔
  • 수행 불가시 인터프리터가 자동 호출

예외 처리 (Exception Handling)

  • 예외가 발생할 경우 후속 조치 등 대처 필요

1) 없는 파일 호출 -> 파일 없음을 알림 2) 게임 이상 종료 -> 게임 정보 저장

프로그램 = 제품, 모든 잘못된 상황에 대처가 필요

 

Exception Handling

파이썬의 예외 처리

  • try~except 문법

try:

예외 발생 가능 코드

except <'Exception Type'>:

예외 발생시 대응하는 코드

 

파이썬의 예외 처리 예시

  • 0으로 숫자를 나눌 때 예외처리하기
for i in range(10):
    try:
        print(10 / i)
    except ZeroDivisionError:
        print("Not divided by 0")
Not divided by 0
10.0
5.0
3.3333333333333335
2.5
2.0
1.6666666666666667
1.4285714285714286
1.25
1.1111111111111112

a = [1,2,3,4,5]
for i in range(10):
    try:
        print(i, 10 // i)
        print(a[i])
        print(v)
    except ZeroDivisionError:
        print("Error")
        print("Not divided by 0")
    except IndexError as e:
        print(e)
    except Exception as e:
        print(e)
Error
Not divided by 0
1 10
2
name 'v' is not defined
2 5
3
name 'v' is not defined
3 3
4
name 'v' is not defined
4 2
5
name 'v' is not defined
5 2
list index out of range
6 1
list index out of range
7 1
list index out of range
8 1
list index out of range
9 1
list index out of range

exception의 종류

  • Built-in Exception: 기본적으로 제공하는 예외
  • IndexError: List의 Index 범위를 넘어갈 때
  • NameErro: 존재하지 않은 변수를 호출할 때
  • ZeroDivisionError: 0으로 숫자를 나눌 때
  • ValueError: 변환할 수 없는 문자/숫자를 변환할 때
  • FileNotFoundError: 존재하지 않는 파일을 호출할 때
  • 예외 정보 표시하기
from datetime import datetime

for i in range(10):
    try:
        print(10 / i)
        a[i]
    except ZeroDivisionError as err:
        print(err)
        print("{}Not divided by 0".format(
            datetime.now()
        ))
    except Exception as e:
        print (e)
division by zero
2022-12-26 04:02:40.405537Not divided by 0
10.0
5.0
3.3333333333333335
2.5
2.0
list index out of range
1.6666666666666667
list index out of range
1.4285714285714286
list index out of range
1.25
list index out of range
1.1111111111111112
list index out of range

for i in range(10):
    try:
        result = 10 // i
    except ZeroDivisionError:
        print("Not divided by 0")
    else:
        print(10 // i)
Not divided by 0
10
5
3
2
2
1
1
1
1

for i in range(0. 10):
    try:
        result = 10 // i
    except ZeroDivisionError:
        print("Not divided by 0")
    else:
        print(10 // i)
    finally:

else 구문

  • try ~ except ~ else
try:
    예외 발생 가능 코드
except <Exception Type>
    예외 발생시 동작하는 코드
else:
    예외가 발생하지 않을 때 동작하는 코드

finally 구문

  • try ~ except ~ finally
try:
    예외 발생 가능 코드
except <Exception Type>:
    예외 발생시 동작하는 코드
finally:
    예외 발생 여부와 상관없이 실행됨
    
try:
    for i in range(1, 10):
        result = 10 // i
        print(result)
except ZeroDivisionError:
    print("Not divided by 0")
finally:
    print("종료되었습니다.")
10
5
3
2
2
1
1
1
1
종료되었습니다.

for i in range(0, 10):
    try:
        result = 10 // i
    except ZeroDivisionError:
        print("Not divided by 0")
    else:
        print(10 // i)
    finally:
        print(i, "------", result)
Not divided by 0
0 ------ 1
10
1 ------ 10
5
2 ------ 5
3
3 ------ 3
2
4 ------ 2
2
5 ------ 2
1
6 ------ 1
1
7 ------ 1
1
8 ------ 1
1
9 ------ 1

raise 구문

  • 필요에 따라 강제로 Exception을 발생
raise <Exception Type> (예외정보)

while True:
    value = input("반환할 정수 값을 입력해주세요")
    for digit in value:
        if digit not in "0123456789":
            raise ValueError("숫자값을 입력하지 않으셨습니다")
    print("정수값으로 반환된 숫자 -", int(value))
반환할 정수 값을 입력해주세요50
정수값으로 반환된 숫자 - 50
정수값으로 반환된 숫자 - 50
반환할 정수 값을 입력해주세요2
정수값으로 반환된 숫자 - 2

assert 구문

  • 특정 조건에 만족하지 않을 경우 예외 발생

assesrt 예외조건

def get_binary_number(decimal_number : int):
    assert isinstance(decimal_number, int)
    return bin(decimal_number)

print(get_binary_number(10.0))

File Handling

Overview File system, 파일 시스템 OS에서 파일을 저장하는 트리구조 저장 체계

File from wiki 컴퓨터 등의 기기에서 의미 있는 정보를 담는 논리적인 단위 모든 프로그램은 파일로 구성되어 있고, 파일을 사용한다.

 

파일의 종류

  • 기본적인 파일 종류로 text파일과 binary파일로 나눔
  • 컴퓨터는 text파일을 처리하기 위해 binary파일로 변환시킴 (예: pyc파일)
  • 모든 text파일도 실제는 binary파일, ASC2/Unicode 문자열 집합으로 저장되어 사람이 읽을 수 있음

  Binary파일

  • 컴퓨터만 이해할 수 있는 형태인 이진(법) 형식으로 저장된 파일
  • 일반적으로 메모장으로 열면 내용이 꺠져 보임 (메모방 해설 불가)
  • 엑셀파일, 워드파일 등등

  Text파일

  • 인간도 이해할 수 있는 형태인 문자열 형식으로 저장된 파일
  • 메모장으로 열면 내용 확인 가능
  • 메모장에 저장된 파일, HTML파일, 파이썬 코드파일 등
def get_binary_number(decimal_number : int):
    assert isinstance(decimal_number, int)
    return bin(decimal_number)

print(get_binary_number(10.0))

Python File I/O

  • 파이썬은 파일 처리를 위해 "open" 키워드를 사용함
f = open("<파일이름>", "접근 모드")
f.close()

파일 열기 모드

  • r: 읽기 모드 - 파일을 읽기만 할 때 사용
  • w: 쓰기 모드 - 파일에 내용을 쓸 때 사용
  • a: 추가모드 - 파일의 마지막에 새로운 내용을 추가시킬 때 사용

파이썬의 File Read

read() txt파일 안에 있는 내용을 문자열로 반환

f = open("i_have_a_drea.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_haver_a_dream.txt", "r") as f:
    content_list = f.readlines()    #파일 전체를 list로 반환
    print(type(content_list))       #Type 확인
    print(content_list)             #리스트 값 출력

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

with open("i_have_a_dream.txt", "r") as f:
    i = 0
    while True:
        line = f.readline()
        if not line:
            break
        print (str(i) + " === " + line.replace("\n",""))    #한줄씩 값 출력
        i = i + 1
        
with open("i_have_a_dream.txt", "r") as my_file:
    contents = my_file.read()
    word_list = contents.split(" ")
    line_list = contents.split("\n")

print("Total Number of Characters :", len(contents))
print("Total Number of Words :", len(word_list))
print("Total Number of Lines :", len(line_list))

#Total Number of Characters : 9198
#Total Number of Words : 1656
#Total Number of Lines : 87

파이썬의 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 다루기

import os
os.mkdir("log")

디렉터리가 있는지 확인하기

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

OS module

import os
os.mkdir("sungchul")

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

os.path.exists("abc")
True

os.path.isfile("file.ipynb")
False

import shutil

source = "i_have_a_dream.txt"
dest = os.path.join("abc", "sungchul.txt")
shutil.copy(source, dest)

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

TARGET_FILE_PATH = os.path.join("log", "count_log.txt")
if not os.path.exists(TARGET_FILE_PATH):
    f = open("log/count_log.txt", 'w', encoding="utf8")
    f.write("기록이 시작됩니다\n")

os 모듈을 사용하여 Directory 다루기

import os
os.mkdir("log")

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

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

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

import pathlib

cwd = pathlib.Path.cwd()
cwd
PosixPath('/content')

cwd.parent
PosixPath('/')

list(cwd.parents)
[PosixPath('/')]

list(cwd.glob("*"))
[PosixPath('/content/.config'),
 PosixPath('/content/count_log.txt'),
 PosixPath('/content/sungchul'),
 PosixPath('/content/abc'),
 PosixPath('/content/log'),
 PosixPath('/content/sample_data')]
 
 import os
if not os.path.exists("log"):
    os.mkdir("log")

TARGET_FILE_PATH = os.path.join("log", "count_log.txt")
if not os.path.exists(TARGET_FILE_PATH):
    f = open("log/count_log.txt", 'w', encoding="utf8")
    f.write("기록이 시작됩니다\n")
    f.close()

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" )
test = [1, 2, 3, 4, 5]
pickle.dump(test, f)
f.close()

test
[1, 2, 3, 4, 5]

test_pickle = 0
test_pickle
0

f = open("list.pickle", "rb")
test_pickle = pickle.load(f)
print(test_pickle)
f.close()
[1, 2, 3, 4, 5]

test_pickle
[1, 2, 3, 4, 5]

import pickle

class Mutltiply(object):
    def __init__(self, multiplier):
        self.multiplier = multiplier

    def multiply(self, number):
        return number * self.multiplier

muliply = Mutltiply(5)
muliply.multiply(10)
50

f = open("multiply_object.pickle", "wb")
pickle.dump(muliply, f)
f.close()

del muliply
muliply
NameError: name 'muliply' is not defined

f = open("multiply_object.pickle", "rb")
multiply_pickle = pickle.load(f)

multiply_pickle
<__main__.Mutltiply at 0x7f3aa545fd60>

multiply_pickle.multiply(100)
500

Logging Handling

게임을 만들었는데, HACK 쓰는 애들 때문에 망했어요.

 

로그 남기기 - Logging

  • 프로그램이 실행되는 동안 일어나는 정보를 기록으로 남기기
  • 유저의 접근, 프로그램의 Exception, 특정 함수의 사용
  • Console 화면에 출력, 파일에 남기기, DB에 남기기 등등
  • 기록된 로그를 분석하여 의미 있는 결과를 도출할 수 있음
  • 실행시점에서 남겨야 하는 기록, 개발시점에서 남겨야 하는 기록

print vs logging

  • 기록을 print로 남기는 것도 가능함
  • 그러나 Console 창에만 남기는 기록은 분석 시 사용불가
  • 때로는 레벨별(개발, 운영)로 기록을 남길 필요도 있음
  • 모듈별로 별도의 logging을 남길 필요도 있음
  • 이러한 기능을 체계적으로 지원하는 모듈이 필요함

logging 모듈

  • Python의 기본 Log관리 모듈
import logging

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

logging level

  • 프로그램 진행 상황에 따라 다른 Level의 Log를 출력함
  • 개발 시점, 운영 시점마다 다른 Log가 남을 수 있도록 지원함
  • DEBUG > INFO > WARNING > ERROR > Critical
  • Log 관리 시 가장 기본이 되는 설정 정보
Level 개요 예시
debug 개발시 처리 기록을 남겨야하는 로그 정보를 남김 - 다음 함수로 A를 호출
- 변수 A를 무엇으로 변경함 
info 처리가 진행되는 동안의 정보를 알림 - 서버가 시작되었음
- 서버가 종료됨
- 사용자 A가 프로그램에 접속함
warning 개발시 처리 기록을 남겨야하는 로그 정보를 남김 - 다음 함수로 A를 호출
- 변수 A를 무엇으로 변경함
error 잘못된 처리로 인해 에러가 났으나, 프로그램은 동작할 수 있음을 알림 - 파일에 기록할 파일이 없음
→ Exception 처리 후 사용자에게 알림
- 외부서비스와 연결 불가
critical
잘못된 처리로 데이터 손실이 나 더이상 프로그램이 동작할 수 없음을 알림
- 잘못된 접근으로 해당 파일이 삭제됨
- 사용자에 의한 강제 종료
import logging

if __name__ == '__main__':
    logger = logging.getLogger("main")
    logging.basicConfig(level=logging.DEBUG)
    logger.setLevel(logging.INFO)

    steam_handler = logging.FileHandler(
        "my.log", mode="w", encoding="utf8")
    logger.addHandler(steam_handler)

    logger.debug("틀렸어!!")
    logger.info("확인행!!")
    logger.warning("조심해!!")
    logger.error("에러났어!!")
    logger.critical("망했다!!")
INFO:main:확인행!!
WARNING:main:조심해!!
ERROR:main:에러났어!!
CRITICAL:main:망했다!!

실제 프로그램을 실행할 땐 여러 설정이 필요. 데이터 파일 위치, 파일 저장 장소 Operation Type 등 이러한 정보를 설정해줄 방법이 필요.

1) configparser - 파일

2) argparser - 실행 시점

 

configparser

  • 프로그램의 실행 설정을 file에 저장함
  • Section, Key, Value 값의 형태로 설정된 설정 파일을 사용
  • 설정파일을 Dict Type으로 호출 후 사용

config file

'example.cfg'

[SectionOne] #Section - 대괄호

  • status: Single #속성 - Key: Value
  • Name: Derek
  • Value: Yes
  • Age: 30
  • Single: True

[SectionTwo]

  • FavoriteColor = Green

[SectionThree]

  • FamilyName: Johnson
import configparser
config = configparser.ConfigParser()
config.sections()

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

for key in config['SectionOne']:
    print(key)

config['SectionOne']["status"]

argparser

  • Console 창에서 프로그램 실행시 Setting 정보를 저장함
  • 거의 모든 Console 기반 Python 프로그램 기본으로 제공
  • 특수 모듈도 많이 존재하지만(TF), 일반적으로 argparse를 사용
  • Command-Line Option이라고 부름
import argparse

parser = argparse.ArgumentParser(
    description='Sum two integers.')

parser.add_argument('-a', "--a_value", dest="A_value", help="A integers", type=int)
parser.add_argument('-b', "--b_value", dest="B_value", help="B integers", type=int)

args = parser.parse_args()
print(args)
print(args.a)
print(args.b)
print(args.a + args.b)

Logging 적용하기

  • Log의 결괏값의 format을 지정해줄 수 있음
formatter = logging.Formatter('%(asctimes %(levelname)s %(process)d %(message)s')

logging.config.fileConfig('logging.conf')
logger = logging.getLogger()

'BOOTCAMP > boostcamp AI Tech Pre-Course' 카테고리의 다른 글

선형독립과 선형종속  (0) 2023.01.01
선형방정식과 선형시스템  (0) 2022.12.29
Mathematics for Artificial Intelligence  (0) 2022.12.28
Numerical Python - numpy  (0) 2022.12.28
Module and Project  (0) 2022.12.27