본문 바로가기
NLP/AI 이론

[Python] Python File/Exception/Log Handler

by ㅣlㅣl 2024. 1. 28.

네이버 부스트코스에서 제공하는 최성철 님의 강의를 참고하여 작성된 포스팅입니다.


 

File / Exception / Log handler

예외 (Exception)

예상 가능한 예외

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

 

예상 불가능한 예외

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

 

보통 예상이 가능한 예외는 if문을 사용, 예상 불가능한 예외는 exception handling 사용

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

프로그램은 제품이므로 모든 잘못된 상황에 대처가 필요하다.

 

try ~ except

try:
    예외 발생 가능
except <Exception Type>:
    예외 발생 대응 코드

if 문이랑 비슷하지만 try ~ except를 예외처리에 더 권장

  • if : 로직적인 문제
  • except : 잘못된 입력, 잘못된 데이터
for i in range(10):
    try:
        print(10/i)
    except ZeroDivisionError:
        print("Not divided by 0")
for i in range(10):
    try:
        print(10/i)
    except ZeroDivisionError as e: # 에러를 e 변수에 할당
        print(e, " : Not divided by 0") # 예외 정보 표시
for i in range(10):
    try:
        print(10/i)
    except ZeroDivisionError as e: # 0으로 나눴을 때 에러, 에러를 e 변수에 할당
        print(e, " : Not divided by 0") # 예외 정보 표시
    except IndexError as e: # 인덱스 에러
        print(e)
    except Exception as e: # 전체 에러
        print(e)

전체 에러는 어느 문제로 에러가 발생했는지 파악하기 힘들어지기 때문에 사용 권장 X

 

try ~ except ~ else

try:
    예외 발생 가능
except <Exception Type>:
    예외 발생 대응 코드
else:
    예외가 발생하지 않을 때

 

try ~ except ~ finally

try:
    예외 발생 가능
except <Exception Type>:
    예외 발생 대응 코드
finally:
    예외 발생 여부와 상관없이 실행

 

built-in exception

 

raise

필요에 따라 강제로 exception 발생 → 종료 시켜서 메모리를 절약할 수 있음

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

 

assert

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

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

print(get_binary_number(10))

 

File Handling (Binary vs Text)

binary → 프로그램 종속적 / text → 프로그램 독립적

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

 

 

File read

파일 형식은 항상 utf-8로 저장하는게 좋음 → cp949는 운영체제 (맥/윈도우) 에 따라 이슈 발생

f = open("i_have_a_dream.txt","r")
contents =f.read()
print(contents)
f.close()

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

with open("i_have_a_dream.txt","r")as my_file:
    content_list =my_file.readlines()#파일 전체를 list로 반환
    print(type(content_list))#Type 확인
    print(content_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

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

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

 

파이썬 directory

import os
os.mkdir("log")

# 디렉토리 있는지 확인
if not os.path.isdir("log"):
    os.mkdir("log")

source = "i_have_a_dream.txt"
dest = os.path.join("abc", "sungchul.txt")
  • path를 문자열 concat으로 넣지 않는 이유는 운영체제에 따라 seperator가 다르기 때문
    • shutil 패키지 : 파일과 폴더 이동 및 복사
    • 5) shutil 모듈 포스팅 참고
# path를 객체로 다루기
import pathlib
cwd = pathlib.Path.cwd() # 현재 path

cwd.parent # 부모 path
list(cwd.parents) # 부모들의 path

list(cwd.glob("*.py")) # 일치하는 모든 파일

 

log 파일 생성

os.path + file w/o

# 디렉토리와 파일 존재 유무 확인
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

파이썬의 객체를 영속화하는 built-in 객체

객체는 원래 메모리에 있음 → 인터프리터 끝날 경우 같이 종료됨

  • 영속화 : 저장한 후 이후에도 쓸 수 있도록 하기그것이 코드 자체라면 문제가 되지 않지만, 코드가 실행되며 발생되는 배열, 사전 등의 객체라든가 특정 전처리가 완료된 데이터에 대해 연산이 진행된 클래스라든가, 하는 경우에는 그것을 따로 저장할 방법이 필요한데 그것이 파이썬에서는 pickle이다.
  • 프로젝트를 진행하다보면 현재 메모리가 임시로 가지고 있는 값 자체를 영구적으로 저장해 놓았다가 다시 재사용해야 하는 경우들이 있다.(주피터 노트북에서 임시로 전처리를 진행중이라든가, 구글 코랩을 활용하는 상황 등등)
import pickle
f = open("list.pickle", "wb")
test = [1, 2, 3, 4, 5]
pickle.dump(test, f)
f.close()

f = open("list.pickle", "rb")
test_pickle = pickle.load(f)
print(test_pickle)
f.close()
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)

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

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

 

Logging handling

  • 프로그램이 실행되는 동안 일어나는 정보를 기록을 남기기
  • 로그 주요 정보
  • 유저의 접근,프로그램의 Exception,특정 함수의 사용
  • 로그를 어디에 남길까?
  • Console 화면에 출력,파일에 남기기,DB에 남기기 등등
  • 기록된 로그를 분석하여 의미 있는 결과를 도출 할 수 있음
  • 실행시점에서 남겨야 하는 기록, 개발시점에서 남겨야하는 기록
import logging
logging.debug("틀렸잖아!")
logging.info("확인해")
logging.warning("조심해!")
logging.error("에러났어!!!")
logging.critical ("망했다...")
  • 프로그램 진행 상황에 따라 다른 level의 log 출력<주로 사용되는 레벨>
    • DEBUG : 개발 단계
    • INFO, WARNING : 운영 단계
    • ERROR, critical : 사용자에게 까지
  • DEBUG>INFO>WARNING>ERROR>Critical
import logging

logger = logging.getLogger("main") # logger 선언
stream_hander = logging.StreamHandler() # logger output 방법 선언 - 출력을 어디로 할지?
logger.addHandler(stream_hander) # logger output 등록
import logging

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

    stream_handler = logging.FileHandler("my.log", mode="w", encoding="utf8") # 파일에 로그 출력
    logger.addHandler(stream_handler)

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

##########################

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

실제 로그를 찍기 위해서는 세팅해야 하는게 많음 (로그 파일, 레벨..)

 

configparser - 파일에서 설정

  • 프로그램의 실행 설정을 file에 저장
  • section - key - value
  • 설정 파일을 Dict Type으로 호출 후 사용
[SectionOne] # 섹션 : 대괄호
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() # 모든 섹션의 이름 가져오기

# config는 객체 형태로 반환됨
for key in config['SectionOne']:
    print(key) 

config['SectionOne']["status"]

configparser — 구성 파일 구문 분석기

[Python] Configparser 사용법( File properties )

 

argparser - 실행 시점에 설정

  • 콘솔 창에서 실행 시 setting 정보를 저장
import argparse
parser = argparse.ArgumentParser(description='Sum two integers.')
# 짧은 이름, 긴 이름, 표시명, help(설명), argument type
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) # property 처럼 접근 가능
print(args.b)
print(args.a + args.b)

argparse — 명령행 옵션, 인자와 부속 명령을 위한 파서

Argparse 자습서

→ 실험할 때 많이 쓰임!! 반드시 잘 익힐 것

 

logging formmater

로그 결과의 포맷 지정

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

 

log config file

logging.config.fileConfig('logging.conf')
logger = logging.getLogger()
logger.info('Open file {0}'.format("customers.csv",))
try:
    with open("customers.csv","r")as customer_data:
        customer_reader = csv.reader(customer_data,delimiter=',',quotechar='"')
    for customer in customer_reader:
        if customer[10].upper()== "USA":#customer 데이터의 offset 10번째 값
            logger.info('ID{0}added'.format(customer[0],))
            customer_USA_only_list.append(customer)#즉 country 필드가 “USA” 것만
except FileNotFoundError as e:
logger.error('File NOTfound {0}'.format(e,))

'NLP > AI 이론' 카테고리의 다른 글

[AI Math] 벡터와 행렬의 개념  (1) 2024.01.28
[Python] NumPy & Pandas  (1) 2024.01.28
[Python] Python Data Handling  (1) 2024.01.28
[Python] OOP + 파이썬 모듈화  (1) 2024.01.28
[Python] 파이썬이란?  (1) 2024.01.28