본문 바로가기
Programming Language/Python

[파이썬] DAY8 자동차 문제 파일 입출력 + 예외처리 적용하기

by 9루트 2022. 1. 25.

과제 요약

입력: 각 자동차의 6개 품목 데이터
정보 하나당 객체로 구현해야하고, 기능 모두 정상 동작
구매가격 = 엔진 가격 + 타이어 가격 * 4 + 1000

 

 

 

클래스 선언

class Info:
  def __init__(self):
    self.name = ""
    self.engine = 0
    self.tire = 0
    self.have_option = ""
    self.option = ""
    self.velocity = 0
    self.price = 0

start_text =  """
#### 자동차 정보 프로그램 ####
1. 자동차 정보 입력
2. 저장된 목록 보기
3. 각 자동차의 구매 가격 조회
4. 옵션이 있는 자동차 정보 조회
5. 빠른 자동차와 느린 자동차의 속도차 조회
6. 프로그램 이용 종료
###########################
입력 : """

 

1. 자동차 정보 입력 

car_lst = []
while True:
  category = input(start_text)

  if category == '1':
    car = Info()
    car.name = input("이름 : ")
    car.engine = int(input("엔진 가격 : "))
    car.tire = int(input("타이어 가격 : "))
    car.have_option = input("옵션 여부 : ")
    car.option = input("옵션 이름 : ")
    car.velocity = int(input("최고 속도 : "))
    car.price = car.engine + car.tire + 1000

    # 리스트에 차 정보 넣기
    car_lst.append(car)

위처럼 자동차 정보 목록을 입력한다.

 

 


2. 저장된 목록 보기

 
  elif category == '2':
    global car_list
    for i in range(0, len(car_lst)):
      print('이름 : ', car_lst[i].name)
      print('엔진 가격 : ', car_lst[i].engine)
      print('타이어 가격 : ', car_lst[i].tire)
      print('옵션 여부(있음/없음) : ', car_lst[i].have_option)
      print('옵션 이름 : ', car_lst[i].option)
      print('최고 속도 : ', car_lst[i].velocity)
      print()

저장된 자동차 데이터들이 출력된다.


3. 각 자동차의 구매가격 조회

  elif category == '3':
    car_name = input("조회할 자동차 이름 : ")
    for i in range(0, len(car_lst)):
      if car_lst[i].name == car_name:
        print(car_name,'의 구매 가격은 ',car_lst[i].price,' 입니다.')


4. 옵션이 있는 자동차 정보 조회

  elif category == '4':
    for i in range(0, len(car_lst)):
      if car_lst[i].have_option == '있음':
        print(car_lst[i].name,'\t의 옵션 : ',car_lst[i].option)

 


5. 빠른 자동차와 느린 자동차 속도차 조회

  elif category == '5':
    max = car_lst[0].velocity
    min = car_lst[0].velocity
    for i in range(0, len(car_lst)):
      if car_lst[i].velocity >= max :
        max = car_lst[i].velocity
      if car_lst[i].velocity <= min :
        min = car_lst[i].velocity
    print(max,'-', min,'=', max - min)


6. 프로그램 이용 종료

  elif category == '6':
    print("서비스 종료합니다.")
    print("감사합니다.")
    break
    
  else:
    print("잘못된 카테고리 입력입니다.")

 

 

위처럼 잘못된 카테고리 입력이라고 뜬다.

 

 

최종 코드

class Info:
  def __init__(self):
    self.name = ""
    self.engine = 0
    self.tire = 0
    self.have_option = ""
    self.option = ""
    self.velocity = 0
    self.price = 0

start_text =  """
#### 자동차 정보 프로그램 ####
1. 자동차 정보 입력
2. 저장된 목록 보기
3. 각 자동차의 구매 가격 조회
4. 옵션이 있는 자동차 정보 조회
5. 빠른 자동차와 느린 자동차의 속도차 조회
6. 프로그램 이용 종료
###########################
입력 : """



car_lst = []
while True:
  category = input(start_text)

  if category == '1':
    car = Info()
    car.name = input("이름 : ")
    car.engine = int(input("엔진 가격 : "))
    car.tire = int(input("타이어 가격 : "))
    car.have_option = input("옵션 여부 : ")
    car.option = input("옵션 이름 : ")
    car.velocity = int(input("최고 속도 : "))
    car.price = car.engine + car.tire + 1000

    # 리스트에 차 정보 넣기
    car_lst.append(car)
    

  elif category == '2':
    global car_list
    for i in range(0, len(car_lst)):
      print('이름 : ', car_lst[i].name)
      print('엔진 가격 : ', car_lst[i].engine)
      print('타이어 가격 : ', car_lst[i].tire)
      print('옵션 여부(있음/없음) : ', car_lst[i].have_option)
      print('옵션 이름 : ', car_lst[i].option)
      print('최고 속도 : ', car_lst[i].velocity)
      print()

  elif category == '3':
    car_name = input("조회할 자동차 이름 : ")
    for i in range(0, len(car_lst)):
      if car_lst[i].name == car_name:
        print(car_name,'의 구매 가격은 ',car_lst[i].price,' 입니다.')
    
    
  elif category == '4':
    for i in range(0, len(car_lst)):
      if car_lst[i].have_option == '있음':
        print(car_lst[i].name,'\t의 옵션 : ',car_lst[i].option)

  elif category == '5':
    max = car_lst[0].velocity
    min = car_lst[0].velocity
    for i in range(0, len(car_lst)):
      if car_lst[i].velocity >= max :
        max = car_lst[i].velocity
      if car_lst[i].velocity <= min :
        min = car_lst[i].velocity
    print(max,'-', min,'=', max - min)


  elif category == '6':
    print("서비스 종료합니다.")
    print("감사합니다.")
    break
    
  else:
    print("잘못된 카테고리 입력입니다.")

자동차 코드에 파일 입출력(pickle) 이용해서 파일에 저장해서 입출력해보기

기본적인 예외 처리 : 파일 없을 때 쓰기(25분)

 

변경한 코드

class save_data: # 클래스를 만든다.
    def __init__(self,name,E_price,T_price,option,opting_N,max_V,all_price): # 7항목의 인스턴스 필드를 초기화해주는 생성자
        self.__name=name
        self.__E_price=E_price
        self.__T_price=T_price
        self.__option=option
        self.__opting_N=opting_N
        self.__max_V=max_V
        self.__all_price=all_price

    # 각각의 은닉된 인스턴스 필드를 get 해주는 인스턴스 메소드를 만든다.
    def getname(self):return self.__name
    def getE_price(self):return self.__E_price
    def getT_price(self):return self.__T_price
    def getoption(self):return self.__option
    def	getopting_N(self):return self.__opting_N
    def	getmax_V(self):return self.__max_V
    def	getall_price(self):return self.__all_price
	
# 밑에 함수들은 클래스와 관련 있지 않고 각각 다른 영역에 해당한다.  
def print_UI(): # """를 이용하여 아래 글 형식 그대로 출력할 수 있게 해준다.
    print("""
########### 자동차 정보 프로그램 ###########
 1. 자동차 정보 입력
 2. 저장된 목록 보기
 3. 각 자동차의 구매 가격 조회
 4. 옵션이 있는 자동차 정보 조회
 5. 빠른 자동차와 느린 자동차의 속도 차 조회
 6. 프로그램 이용 종료
############################################""")
def mode(): # 메인 영역에 들어갈 내용을 mode()라는 함수에 넣는다.
    print_UI() # 공지글 함수를 넣는다.
    menu=int(input("입력:"))
    if menu==1:
        enter() 
        return True # 함수이므로 run에 대한 값을 반환해준다. 
        # while True: 로 해주고 break로 해주는 경우 while else 문에서 else 문을 지나가기 어렵다.
    elif menu==2:
        view()
        return True
    elif menu==3:
        search_P()
        return True
    elif menu==4:
        search_Op()
        return True
    elif menu==5:
        speed_C()
        return True
    elif menu==6:
        print("프로그램이 종료됩니다.")
        return False # 완전히 종료하기 위해 run == False로 반환해준다.
    else:
        print("잘못 입력 하셧습니다.\n 다시 입력해주세요.")
        return True

def enter():
    global data_list # 리스트는 mutable 객체이기 때문에 굳이 global 을 쓸 필요 없지만 그래도 통일성을 위해 써준다.----------------------
    global max_s # int는 immutable 객체이기 때문에 global을 써준다.
    global min_s # int는 immutable 객체이기 때문에 global을 써준다.
    name=input("이름 입력 :")
    E_price=int(input("엔진가격 입력 :"))
    T_price=int(input("타이어가격 입력 :"))
    option=input("옵션유무 입력 (있음/없음):")
    option_N=""# 이걸 생각 못 했네 옵션 여부에 "없음"이 입력되면 옵션에 "없음"이 자동 입력,--------------------------------
    if (option=="없음"):
        option_N="없음"
    else:
        option_N=input("옵션이름 입력 :") # 옵션이 있으면 옵션 이름을 따로 넣는 입력란을 넣는다.

    max_V=int(input("최고속력 입력 :")) # 최고 속력을 입력하는 즉시 max min와 비교한다. - 합리적인 코드다.
    if (max_V>max_s): max_s=max_V
    if (max_V<min_s): min_s=max_V
    all_price = E_price+T_price # 총 가격 계산도 입력할 때 클래스가 아닌 함수 내에서 계산하도록 한다.
    print(f"구매가격 :{all_price}")
    car_data =save_data(name,E_price,T_price,option,option_N,max_V,all_price) # 자동차 정보의 7가지 항목에 대해 인스턴스를 생성한다.
    data_list.append(car_data) # 각 인스턴스를 리스트 각 인덱스에 입력한 차례로 넣어준다.
    print("차량이 등록되었습니다.")

def view():
    global data_list # 각 차에 대한 정보가 있는 리스트를 전역변수로 만들어준다. --------------------??????????????
    if (len(data_list)<=0): # 리스트에 어떠한 데이터도 없으면 차량이 없다는 문구를 출력한다.
        print("등록 된 차량이 없습니다.")
        return # 반드시 함수이므로 break 대신 return을 넣어준다.
    else:
        print("--------------")
        print("차량 목록")
        print("--------------")
        print("이름|타이어가격|엔진가격|옵션유무|옵션이름|최고속도|구매가격")
        for i in  data_list:# 와 이렇게 표현할 수도 있구나 인덱스 번호가 아닌 해당 인덱스에 대한 각 공간을 i로 넣어버림  ------------------------------------------------------------------
            car_data = i
            if(car_data != None):# ---------------------------------------------------?????????????
                print(car_data.getname(),end="  |  ")
                print(car_data.getE_price(),end="  |  ")
                print(car_data.getT_price(),end="  |  ")
                print(car_data.getoption(),end="  |  ")
                print(car_data.getopting_N(),end="  |  ")
                print(car_data.getmax_V(),end="  |  ")
                print(car_data.getall_price(),end="  |  ")
                print()

def search_P():
    global data_list
    if (len(data_list)<=0): # 진짜 꼼꼼하시다. 등록된 차량이 없는 경우도 고려한다.
        print("등록 된 차량이 없습니다.")
        return
    else:
        print("--------------")
        print("구매가격조회")
        print("--------------")
        print("이름|구매가격")
        for i in  data_list:
            car_data = i
            if(car_data != None):# 이런 식으로 혹시나 해당 리스트에 데이터가 없는 경우도 생각해준다.
                print(car_data.getname(),end="|")
                print(car_data.getall_price())
def search_Op():
    global data_list
    if (len(data_list)<=0):
        print("등록 된 차량이 없습니다.")
        return
    else:
        print("--------------")
        print("옵션있는 차량 조회")
        print("--------------")
        print("이름|타이어가격|엔진가격|옵션이름|최고속도|구매가격")
        for i in  data_list:
            car_data = i
            if(not(car_data.getoption()=="없음")): # 이게 추가 되었네. 옵션이 없는 것은 제외하고 하고 != 보단 not을 붙였다. 
                print(car_data.getname(),end="  |  ")
                print(car_data.getE_price(),end="  |  ")
                print(car_data.getT_price(),end="  |  ")
                print(car_data.getopting_N(),end="  |  ")
                print(car_data.getmax_V(),end="  |  ")
                print(car_data.getall_price(),end="  |  ")
                print()
def speed_C():
    if (len(data_list)<2): # 어떻게 이런 생각을 하셨지.. 그러니까 대소 비교를 위해서는 적어도 2대 이상이 필요한데
    # 두 대 이상이 아닐 경우 최고 최저 속도 차량 없다고 쓴다.
    # 하지만 아예 리스트에 차량이 없으면 차량 없다고 뜨고, 한 대만 있으면 최소 최대 속도를 한 대 있는 차량의 속도 값으로 넣어도 되겠다.
        print("2대 이상 등록된 차량이 없습니다.")
        return
    print(f"빠른 자동차와 느린 자동차의 속도차는 {max_s - min_s}입니다.")


#______________________메인영역_________________________________________
import pickle
max_s = 0
min_s = 1000 # 최솟값으로 가장 큰 값을 넣는다.

#리스트를 불러온다.
#####################################################################################     
try:
  o_f = open("saveList.p", "rb")
  data_list = pickle.load(o_f) # 파일 포인터가 이미 데이터를 읽고 이동해버린다.
  # load는 반드시 try에 써주기, 가져온 파일이 있어야 실행되니까.
except IOError:
  print("기존 정보가 저장되어 있는 파일이 없습니다.")
  print("새로운 파일에 저장합니다.")
  data_list=[] # 각 차에 대한 정보를 각 인덱스에 순차적으로 넣는다.
else: # IOError 예외 처리가 동작하지 않았을 때 발생한다.
  print("기존 정보가 저장되어 있는 파일을 불러옵니다.")
  o_f.close()
finally:  # 예외 여부와 상관없이 동작하는 자원을 정리해준다.
#####################################################################################     
  run=True
  while run:
    run=mode()

# 리스트를 저장한다.
#####################################################################################     
i_f = open("saveList.p","wb")
print("새로 저장할 파일을 만듭니다.")

pickle.dump(data_list,i_f)
i_f.close() # 이건 안 써 도 되나 - 어차피 실행이 끝나면 가비지 콜렉터가 처리해주므로 생략할 수 있다.
#####################################################################################