Python - 예외 처리와 로그

TrainToGPB·2023년 6월 4일
0

Python Basics

목록 보기
1/2

Exception Handling

  • 예상 가능한 오류: 발생 여부를 사전에 인지할 수 있는 예외
  • e.g., 사용자의 잘못된 입력, 파일 호출 시 파일 없음 등
  • 개발자가 반드시 명시적으로 정의해야 함
  • 예상 불가능한 오류: 인터프리터 과정에서 발생하는 예외
  • e.g., 리스트 범위를 넘어가는 값의 호출, 정수를 0으로 나눔 등
  • 수행 불가시 인터프리터가 자동 호출

try ~except

  • 예외 처리는 try ~except 문법으로 가능
  • try: 예외 발생 가능 코드
  • except <Exception Type>: 예외 발생시 대응 코드
for i in range(5):
  try:
    print(10 / i)
  except ZeroDivisionError:
    print("Not divided by 0")
Not divided by 0
10.0
5.0
3.3333333333333335
2.5

try ~except ~else

  • else: 예외가 발생하지 않을 때 동작하는 코드
for i in range(5):
  try:
    result = 10 / i
  except ZeroDivisionError:
    print("Not divided by 0")
  else:
    print(10 / i)
Not divided by 0
10.0
5.0
3.3333333333333335
2.5

try ~except ~finally

  • finally: 예외 발생 여부와 상관없이 실행되는 코드
try:
  for i in range(1, 5):
    result = 10 / i
    print(result)
except ZeroDivisionError:
  print("Not divided by 0")
finally:
  print("종료되었습니다.")
10.0
5.0
3.3333333333333335
2.5
종료되었습니다.

raise

  • 필요에 따라 강제로 Exception을 발생
  • raise <Exception Type>(예외정보)
while True:
  value = input("변환할 정수 값을 입력해주세요.")
  for digit in value:
    if digit not in "0123456789":
      raise ValueError("숫자 값을 입력하지 않으셨습니다.")
  print("정수 값으로 변환된 숫자 - ", int(value))
변환할 정수 값을 입력해주세요.123
정수 값으로 변환된 숫자 -  123
변환할 정수 값을 입력해주세요.4-2진도준



---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-7-fa6952095a0f> in <module>
      3   for digit in value:
      4     if digit not in "0123456789":
----> 5       raise ValueError("숫자 값을 입력하지 않으셨습니다.")
      6   print("정수 값으로 변환된 숫자 - ", int(value))


ValueError: 숫자 값을 입력하지 않으셨습니다.

assert

  • 특정 조건에 만족하지 않을 경우 예외 발생
  • assert 예외조건
def get_binary_number(decimal_number):
  assert isinstance(decimal_number, int)
  return bin(decimal_number)[2:]

print(get_binary_number(123))
print(get_binary_number("123"))
1111011



---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-13-1d391be279b8> in <module>
      4 
      5 print(get_binary_number(123))
----> 6 print(get_binary_number("123"))


<ipython-input-13-1d391be279b8> in get_binary_number(decimal_number)
      1 def get_binary_number(decimal_number):
----> 2   assert isinstance(decimal_number, int)
      3   return bin(decimal_number)[2:]
      4 
      5 print(get_binary_number(123))


AssertionError: 

File Handling

  • File system: OS에서 파일을 저장하는 "트리구조" 저장 체계
  • 디렉토리(Directory)
  • 폴더 또는 디렉토리로 불림
  • 파일이나 다른 디렉토리를 포함할 수 있음
  • 파일(File)
  • 컴퓨터에서 정보를 저장하는 논리적 단위
  • 파일은 파일명과 확장자로 식별(e.g., hello.py)
  • 실행, 쓰기, 읽기 등을 할 수 있음

image.png

  • 파일의 종류
  • Text 파일과 Binary 파일로 나뉨
  • 컴퓨터는 보통 text 파일을 처리하기 위해 binary 파일로 변환
  • 모든 text 파일도 실제로는 binary 파일이지만, ASCII/Unicode 문자열 집합으로 저장되기 때문에 사람이 읽을 수 있는 것

Python File I/O

  • 파이썬은 파일의 처리를 위해 "open"을 사용
  • 열기: f = open("<파일이름>", "접근 모드")
  • 닫기: f.close()
  • 파일 접근 모드
  • r: 읽기
  • w: 쓰기
  • a: 추가(마지막에 새로운 내용 추가할 때)
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive

open

folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
f = open(folder_path+"i_have_a_dream.txt", "r")
contents = f.read()
print(contents)
f.close()
I Have a Dream, a song to sing
To help me cope, with anything
If you see the wonder, of a fairy tale
You can take the future, even if you fail
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I Have a Dream, a fantasy
To help me through, reality
And my destination, makes it worth the while
Pushin' through the darkness, still another mile
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I'll cross the stream, I Have a Dream
I Have a Dream, a song to sing
To help me cope, with anything
If you see the wonder, of a fairy tale
You can take the future, even if you fail
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I'll cross the stream, I Have a Dream
  • with open도 자주 사용
  • with 문을 벗어나면 자동으로 close
folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
with open(folder_path+"i_have_a_dream.txt", "r") as my_file:
  contents = my_file.read()
  print(type(contents), contents)
<class 'str'> I Have a Dream, a song to sing
To help me cope, with anything
If you see the wonder, of a fairy tale
You can take the future, even if you fail
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I Have a Dream, a fantasy
To help me through, reality
And my destination, makes it worth the while
Pushin' through the darkness, still another mile
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I'll cross the stream, I Have a Dream
I Have a Dream, a song to sing
To help me cope, with anything
If you see the wonder, of a fairy tale
You can take the future, even if you fail
I believe in angels
Something good in everything I see
I believe in angels
When I know the time is right for me
I'll cross the stream, I Have a Dream
I'll cross the stream, I Have a Dream
  • readline(): 실행 시 마다 한 줄 씩 읽어 오기
folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
with open(folder_path+"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 += 1
0 === I Have a Dream, a song to sing
1 === To help me cope, with anything
2 === If you see the wonder, of a fairy tale
3 === You can take the future, even if you fail
4 === I believe in angels
5 === Something good in everything I see
6 === I believe in angels
7 === When I know the time is right for me
8 === I'll cross the stream, I Have a Dream
9 === I Have a Dream, a fantasy
10 === To help me through, reality
11 === And my destination, makes it worth the while
12 === Pushin' through the darkness, still another mile
13 === I believe in angels
14 === Something good in everything I see
15 === I believe in angels
16 === When I know the time is right for me
17 === I'll cross the stream, I Have a Dream
18 === I'll cross the stream, I Have a Dream
19 === I Have a Dream, a song to sing
20 === To help me cope, with anything
21 === If you see the wonder, of a fairy tale
22 === You can take the future, even if you fail
23 === I believe in angels
24 === Something good in everything I see
25 === I believe in angels
26 === When I know the time is right for me
27 === I'll cross the stream, I Have a Dream
28 === I'll cross the stream, I Have a Dream
  • Text 파일 내 단어 통계 정보 산출
folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
with open(folder_path+"i_have_a_dream.txt", "r") as my_file:
  contents = my_file.read()
  line_list = contents.split("\n") # 한 줄씩 분리한 리스트
  word_list = contents.split(" ") # 빈 칸 기준으로 단어 분리한 리스트
  
print(" Total Number of Characters:", len(contents))
print(" Total Number of Lines:", len(line_list))
print(" Total Number of Words:", len(word_list))
 Total Number of Characters: 959
 Total Number of Lines: 29
 Total Number of Words: 171
  • "w": 쓰기 접근 모드
  • write()로 데이터 쓰기
folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
f = open(folder_path+"i_have_a_dream.txt", "w", encoding="utf8")
for i in range(1, 11):
  data = "%d번째 줄입니다.\n" % i
  f.write(data)
f.close()
  • "a": 내용 추가 접근 모드
  • "w"와 마찬가지로 write() 함수 이용해서 추가
folder_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes/"
with open(folder_path+"i_have_a_dream.txt", "a", encoding="utf8") as f:
  for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    f.write(data)

Directory

os

import os
os.mkdir("log")
# 디렉토리가 있는지 미리 확인하고 없으면 만들기
if not os.path.isdir("log"):
  os.mkdir("log")
  • 최근에는 pathlib 모듈을 사용해 path를 하나의 객체로 다룸
import pathlib
import sys
sys.path.append("/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Codes")
%cd /content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC

cwd = pathlib.Path.cwd()
print(cwd)
print(cwd.parents)
print(list(cwd.parents))
print(list(cwd.glob("*")))

%cd /content
/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC
/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC
<PosixPath.parents>
[PosixPath('/content/drive/MyDrive/Colab Notebooks'), PosixPath('/content/drive/MyDrive'), PosixPath('/content/drive'), PosixPath('/content'), PosixPath('/')]
[PosixPath('/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course')]
/content

Log Handling

  1. 디렉토리 있는지 확인 후 로그 저장을 위한 디렉토리 생성
  2. 로그 파일 있는지 확인 후 로그 파일 생성
import os

log_path = "/content/drive/MyDrive/Colab Notebooks/NAVER_AI_BC/Pre_Course/Materials/log"
if not os.path.isdir(log_path):
  os.mkdir(log_path)
if not os.path.exists(log_path+"/count_log.txt"):
  f = open(log_path+"/count_log.txt", "w", encoding="utf8")
  f.write("기록이 시작됩니다\n")
  f.close()

with open(log_path+"/coung_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)하는 빌트인 객체
  • 데이터, 객체 등 실행 중인 정보를 저장하고, 이후 불러와서 사용 가능
  • 저장해야하는 정보, 모델의 계산 결과 등 활용성이 다양함
import pickle

f = open("list.pickle", "wb") # wb: write byte, pickle은 byte 형식으로 데이터를 읽고 씀
test = [1, 2, 3, 4, 5]
pickle.dump(test, f)
f.close()

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

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

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

my_multiply = Multiply(5)
print(my_multiply.multiply(10))

f = open("my_multiply_object.pickle", "wb")
pickle.dump(my_multiply, f)
f.close()

f = open("my_multiply_object.pickle", "rb")
my_multiply_pickle = pickle.load(f)
my_multiply_pickle.multiply(5)
50





25

Logging

내용이 다소 어려우니 참고:

https://sosoeasy.tistory.com/414#:~:text=logging%EC%9D%80%20%EC%98%A4%EB%A5%98%EC%9D%98%20%EB%B0%9C%EC%83%9D,%EC%98%A4%EB%A5%98%EB%A5%BC%20%ED%99%95%EC%9D%B8%ED%95%A0%20%EC%88%98%20%EC%9E%88%EB%8B%A4.

  • 로그를 남긴다(logging)는 것은, 프로그램이 실행되는 동안 일어나는 정보에 대한 기록을 남기는 것

  • 유저의 접근, 프로그램의 예외 처리, 특정 함수의 사용 등

  • Console 화면에 출력하거나, 파일 또는 DB에 남기는 방식을 사용

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

  • 실행시점/개발시점에서 남겨야 하는 기록이 다름

  • print vs logging

  • Console 창에만 남는 print 기록은 분석시 사용이 불가

  • 떄로는 개발단계/운영단계 등 레벨 별 기록을 따로 남길 필요도 있으며, 모듈 별로 별도 logging이 필요한 경우도 있음

  • 이러한 기능을 체계적으로 지원하는 파이썬 기본 로그 관리 모듈이 "logging"

image.png

  • logging 모듈
  • 프로그램 진행 상황에 따라 다른 레벨의 로그를 출력
  • 개발 시점, 운영 시점마다 다른 로그가 남을 수 있도록 지원
  • debug > info > warning > error > critical
  • 로그 관리시 가장 기본이 되는 설정 정보임
import logging

logging.debug("틀렸잖아!")
logging.info("확인해")
logging.warning("조심해!!")
logging.error("에러났어!!!")
logging.critical("ㅈ됐어...")
import logging

logger = logging.getLogger("main") # Logger 선언
stream_handler = logging.StreamHandler() # Logger의 output 방법 선언
logger.addHandler(stream_handler) # Logger의 output 등록

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("ㅈ됐어...")

Information Settings: configparser & argparser

  • 실제 프로그램을 실행할 때는 여러 설정이 필요함
  • e.g., 데이터 파일 위치, 파일 저장 장소, operation type 등
  • 이러한 정보를 설정해 줄 방법이 필요함

configparser

image.png

  • 프로그램의 실행 설정을 파일에 저장
  • Section, Key, Value 값의 형태로 설정된 설정 파일을 사용
  • 설정 파일을 dict type으로 호출한 후 사용
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 창에서 프로그램 실행시 설정된 정보를 저장
  • 거의 모든 console 기반 파이썬 프로그램 기본으로 제공
  • 특수 모듈도 많이 존재하지만(TF), 일반적으로 argparser 사용
  • Command-Line Option이라고도 부름
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)
print(args.b)
print(args.a + args.b)
  • 파이토치 기반 MNIST 분류 모델 로그파일 저장 예시
def main():
  parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
  parser.add_argument('--batch-size', type=int, default=64, metavar='N', help='input batch size for training (default: 64)')
  parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N', help='input batch size for testing (default: 1000)')
  parser.add_argument('--epochs', type=int, default=10, metavar='N', help='number of epochs to train (default: 10)')
  parser.add_argument('--lr', type=float, default=0.01, metavar='LR', help='learning rate (default: 0.01)')
  parser.add_argument('--momentum', type=float, default=0.5, metavar='M', help='SGD momentum (default: 0.5)')
  parser.add_argument('--no-cuda', action='store_true', default=False, help='disables CUDA training')
  parser.add_argument('--seed', type=int, default=1, metavar='S', help='random seed (default: 1)')
  parser.add_argument('--save-model', action='store_true', default=False, help='For Saving the current Model')
  args = parser.parse_args()

if __name__ == '__main__':
  main()

Logging Application

  • 로그 결과 값 포맷을 지정할 수 있음

image.png

formatter = logging.Formatter("%(asctime)s %(levelname)s %(process)d %(message)s")
  • Log config 파일

image.png

logging.config.fileConfig("logging.conf")
logger = logging.getLogger()
  • logging 예시
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":
        logger.info("ID {0} added".format(customer[0],))
        customer_USA_only_list.append(customer)
except FileNotFoundError as e:
  logger.error("File NOT fount {0}".format(e,))
profile
J의 틀에 몸을 녹여 맞추는 P

0개의 댓글