[Python] Chapter03. 파이썬 중급 문제 풀이(클래스, 예외처리, 텍스트파일 읽/쓰기)

황성미·2023년 7월 16일
0
post-thumbnail
post-custom-banner

✍🏻 14일 & 15일 공부 이야기.
클래스, 예외처리, 텍스트파일 읽/쓰기 예제 문제들을 풀어보았다:)




클래스

자동차 경주 게임 클래스를 만들어보자. 자동차의 속력은 랜덤하게 이동하며, 편의산 10초동안 주행한다고 할 때 가장 멀리 이동한 자동차가 우승하는 게임을 프로그램으로 완성해라.

강의에서는 게임 결과 순위를 출력하는 내용의 코드가 없어서 carRacing.py의 CarRacing 클래스의 rankings 속성이 사용되지 않았었다.

그래서 printResultCarRanking 메서드를 만들어 레이싱 결과를 마지막에 출력해주는 기능을 추가해보았다:)


📄 car.py

import random

class Car:
    def __init__(self, n='fire car', c='red', s=200):
        self.name = n #차 이름
        self.color = c #차 색상
        self.max_speed = s #차의 최고 속력
        self.distance = 0 #처음에는 이동한 거리가 없으니 0으로 설정해둠

    def printCarInfo(self): #차의 정보를 출력해주는 기능
        print(f'name : {self.name}, color : {self.color}, max_speed : {self.max_speed}')

    def controlSpeed(self): #차의 속도를 담당해주는 기능
        return random.randint(0, self.max_speed) #항상 max_speed의 속력으로는 달릴 수 없으므로
        #0부터 max_speed 사이의 난수를 발생시켜 차가 달린다고 가정

    def getDistanceForHour(self): #한시간동안 간 거리를 측정해주는 기능
        return self.controlSpeed() * 1




📄 carRacing.py

from time import sleep #프로그램을 잠시 sleep 시키는 모듈

class CarRacing:

    def __init__(self):
        self.cars = [] #차들이 등록될 리스트
        self.rankings = [] #차들의 순위를 매겨줄 리스트

    def startRacing(self):
        #본 프로그램에선
        #정해진 거리를 누가 먼저 완주하는지를 파악한 것이 아닌,
        #정해진 시간동안(예제에선 10초동안) 누가 더 멀리 갔는지를 기준으로
        #순위를 측정할 예정이다.

        #실제로 1시간 동안 이동거리를 측정하자면
        #프로그램을 1시간동안 계속 돌려야 하는데, 편의상
        #1초를 1시간으로 가정하고 10초 동안 게임을 돌려보도록 할 것임

        for i in range(10): #10초
            print(f'Racing : {i+1}시간 후')
            for car in self.cars:
                car.distance += car.getDistanceForHour() #한 시간마다 이동한 거리를 더해줌
                #여기서 self.cars에 Car 클래스의 객체들이 들어온다면
                #각 객체들의 distance 속성을 이용할 수 있으니
                #car.distance라고 코딩할 수 있음.

            sleep(1) #1초동안 sleep 시켜줌(게임의 재미 요소, 게임 기능과는 무관!)
            self.printCurrentCarDistance() #각 {i+1}시간이 지난 시점의 차들 거리를 보여줌
        self.printResultCarRanking() #마지막 10초를 다 돌았다면, 차들의 순위를 보여줌


    def printCurrentCarDistance(self): #차들의 거리를 보여주는 기능
        for car in self.cars:
            print(f'{car.name} : {car.distance}\t\t' , end = '')
        print()

    def addCar(self, c): #cars 속성에 Car 클래스의 객체들을 넣어주기 위한 기능
        self.cars.append(c)

    ####내가 추가로 코딩한 내용####
    def printResultCarRanking(self): #레이싱 결과를 출력해주는 기능
        distance_result = []

        ##리스트 내 숫자 크기 순서대로 순위 매기는 방법#####################
        ##"몇 번째로 큰 숫자일까?"
        for car in self.cars:
            distance_result.append(car.distance)
        distance_sort = sorted(distance_result) #오름차순 정렬 
        distance_sort.reverse() #내림차순 정렬로 바꿔준 후

        for i in distance_result: #몇 번째 순위인지 알려줌 
            self.rankings.append(distance_sort.index(i) + 1)
        ############################################################
        print('***********************************************')
        print("레이싱의 결과는~!!! 두구두구!!!!!")
        for car in self.cars: #각 차의 이름과 레이싱 순위 결과 출력
            print(f'{car.name} : {self.rankings[self.cars.index(car)]}위\t\t', end='')
        print()
        print('***********************************************')




📄 carRacingStart.py

import carRacing as rc
import car

myCarGame = rc.CarRacing()
car01 = car.Car('Car01','White',250)
car02 = car.Car('Car02', 'Black', 200)
car03 = car.Car('Car03', 'Yellow', 220)
car04 = car.Car('Car04', 'Red', 280)
car05 = car.Car('Car05', 'Blue', 150)

myCarGame.addCar(car01)
myCarGame.addCar(car02)
myCarGame.addCar(car03)
myCarGame.addCar(car04)
myCarGame.addCar(car05)

myCarGame.startRacing()

💻 출력

레이싱 게임 실행 파일인 carRacingStart.py를 실행시키면 위와 같이 출력되는 것을 볼 수 있다. 게임을 만들 때 사용되는 sleep(1) 도 오랜만에 사용해봐서 재밌었다. 1초씩 늦게 결과가 출력되는 것을 보여주려고 gif로 첨부해보았다 😊

리스트 내의 숫자 크기 순서대로 순위를 매기는 printResultCarRanking() 코드는 이 사이트를 참고했다:)




예외처리


1부터 100까지의 소수인 난수 10개를 생성하되, 소수가 아니면 사용자 예외가 발생하도록 하는 프로그램을 완성해라.

📄 primemodule.py

class NotPrimeException(Exception):
  def __init__(self, n):
    super().__init__(f'{n} is not prime number.')

class PrimeException(Exception):
  def __init__(self, n):
    super().__init__(f'{n} is prime number.')

def isPrime(number):
  prime = True

  #소수란, 1과 자기 자신으로만 나누어지는 수를 뜻함
  for n in range(2, number): #따라서 2와 (number - 1)사이의 수 중
    if number % n == 0: #나누어지는 수가 있다면
      prime = False #소수가 아님을 뜻함
      break
  if prime == False:
    raise NotPrimeException(number)
  else:
    raise PrimeException(number)

📄 primestart.py

import primemodule as pm
import random

primeNumbers = []

n = 0
while n < 5: #발견하고 싶은 소수의 개수(5개)
  rn = random.randint(1, 100) #난수 생성

  #1부터 100 중, 중복되지 않은 소수를 발견하고 싶음
  if rn not in pm.primeNumbers: #그래서 primeNumbers 리스트 안에 있는지 확인한 후, 없으면
    #소수인지 아닌지 판별이 들어감
    try:
      pm.isPrime(rn)
    except pm.NotPrimeException as e: #소수가 아니면
      print(e) #아님을 출력해주고
      continue #계속 진행시킴
    except pm.PrimeException as e: #소수이면 
      print(e)
      primeNumbers.append(rn)#primeNumbers 리스트에 넣어줌
  else: #이미 primeNumbers에 있는 숫자면
    print(f'{rn} is overlap number.') #중복된 숫자임을 출력해주고
    continue #계속 진행시킴

print(f"발견된 소수는 다음과 같습니다. {primeNumbers}")
#실제로 1부터 100까지 중 소수는
# 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
#총 25개로 난수를 생성해서 소수를 찾기엔 시간이 많이 소요됨ㅎㅎ

소수를 찾는 알고리즘이 기억에 남아서 정리해보았다. 중복된 소수아기너, 소수가 아닌 수들이 너무 많아서 결과를 첨부할 시간이 부족했다ㅠㅠ





은행 계좌 개설 및 입출금을 할 수 있는 프로그램을 완성해라.


📄 bank.py
<import random #계좌번호를 만들기 위한 난수 생성

class PrivateBank: #계좌
    def __init__(self, bank, account_name):
        self.bank = bank #은행
        self.account_name = account_name #예금주 이름

        while True: #계좌번호 생성(은행에 없는 계좌번호가 나올때까지 생성함)
            newAccountNum = random.randint(10000,99999)
            if bank.isAccount(newAccountNum): #이미 있는 계좌번호는 계속 다시 만들고
                continue
            else: #없는 계좌번호를 설정해준다.
                self.account_num = newAccountNum
                break

        self.totalMoney = 0 #계좌 개설 당시 금액은 0원 들어가있음
        bank.addAccount(self) #계좌 개설 완료

    def printBankInfo(self): #계좌 정보
        print('*' * 40)
        print(f'account_name : {self.account_name}')
        print(f'account_num : {self.account_num}')
        print(f'total Money : {self.totalMoney}')
        print('*' * 40)



class Bank: #은행
    def __init__(self):
        self.accounts = {} #은행의 계좌들 {계좌번호 : 계좌}

    def addAccount(self, privateBank): #계좌 추가
        self.accounts[privateBank.account_num] = privateBank
    def isAccount(self, account_num): #기존 계좌 번호가 있는지 없는지
        return account_num in self.accounts
    def doDeposit(self, account_num, money): #입금
        pb = self.accounts[account_num] #해당 계좌번호에
        pb.totalMoney += money #입금해줌
    def doWithdraw(self, account_num, money): #출금
        pb = self.accounts[account_num] #해당 계좌번호에
        #잔액이 있는지 확인하고
        if pb.totalMoney - money < 0:
            raise LackException(pb.totalMoney, money)
        pb.totalMoney -= money #잔액이 출금액보다 크거나 같으면 출금해줌.

class LackException(Exception):
    def __init__(self, money1, moeny2):
        super().__init__(f'잔고 부족!  잔액 : {money1} , 출금액 : {moeny2}')

📄 bankStart.py
<import bank

korea_Bank = bank.Bank() #은행

new_account_name = input("통장 개설을 위한 예금주 입력 : ")
myAccount = bank.PrivateBank(korea_Bank, new_account_name) #korea은행의 계좌 개설
myAccount.printBankInfo()

while True:
    selectNumber = int(input('1.입금 \t 2.송금 \t 3.종료 '))

    if selectNumber == 1: #입금
        money = int(input("입금액 입력 : "))
        korea_Bank.doDeposit(myAccount.account_num, money)
        myAccount.printBankInfo()
    elif selectNumber == 2: #출금
        money = int(input("출금액 입력 : "))
        try:
            korea_Bank.doWithdraw(myAccount.account_num, money)
        except bank.LackException as e:
            print(e)
        finally:
            myAccount.printBankInfo()
    elif selectNumber == 3: #종료
        print("서비스를 종료하겠습니다. 안녕히가십시오.")
        break
    else:
        print('번호를 잘못 입력하셨습니다!')

은행도 여러 개하고, 계좌번호를 입력해서 입출금을 진행하는 코드를 짜보고 싶었는데.. 코드를 처음부터 다시 짜야할 것 같아서 완성하진 못했다ㅠ
대신 내가 하고 싶은 알고리즘과 비슷하게 구현된 사이트를 찾아서 첨부한다..!

추가
다른 강의들도 듣고 와보니 내가 너무 어렵게 생각했던 것 같다. 지금까지 배운 내용들을 조합하면 빨리 짤 수 있을 것 같다! 코드 짜게 되면 첨부할게요 🥰




텍스트파일 읽/쓰기

회원 계정별 텍스트 파일을 생성한 후 회원 본인 파일에 '한 줄 읽기'를 쓰고 읽는 프로그램을 완성해라.
📄 diary.py

import time

def writeDiary(uri, filename, diary):
    lt = time.localtime()
    timeStr = time.strftime("%Y-%m-%d %I:%M:%S %p", lt)

    filePath = uri + filename

    with open(filePath, 'a') as f:
        f.write(f'[{timeStr}] {diary}\n')



def readDiary(uri, filename):
    filePath = uri + filename
    datas = []

    with open(filePath, 'a') as f:
        datas = f.readlines()

    return datas

📄 diaryStart.py
<import diary

members = {}
uri = 'C:/Users/nabi4/PycharmProjects/pythonProject/제로베이스스쿨/텍스트파일 읽쓰기'

def printMembers():
    for m in members.keys():
        print(f'ID : {m} \t PW : {members[m]}')


while True:
    selectNum = int(input('1.회원가입 2.한줄읽기쓰기, 3.일기보기, 4.종료'))

    if selectNum == 1:
        mId = input("input ID : ")
        mPw = input("input PW : ")
        members[mId] = mPw
        printMembers()

    elif selectNum == 2:
        mId = input("input ID : ")
        mPw = input("input PW : ")

        if mId in members and members[mId] == mPw:
            print("login success!")
            fileName = "myDiary_" + mId + '.txt'
            data = input('오늘 하루 인상 깊은 일을 기록하세요.')
            diary.writeDiary(uri, fileName, data)

        else:
            print("login fail!")
            printMembers()

    elif selectNum == 3:
        mId = input("input ID : ")
        mPw = input("input PW : ")

        if mId in members and members[mId] == mPw:
            print("login success!")
            fileName = "myDiary_" + mId + '.txt'
            data = input('오늘 하루 인상 깊은 일을 기록하세요.')
            datas = diary.readDiary(uri, fileName)

            for d in datas:
                print(d, end='') #readDiary() 자체에 개행을 한 번 해주었기 떄문에 여기선 뺴주어야 원하는 결과를 얻을 수 있음
        else:
            print("login fail!")
            printMembers()


    elif selectNum == 4:
        print("Bye~")
        break

이 알고리즘을 비슷하게 쓰면 위에 은행 입출금 기능도 구현할 수 있을 것 같다는 생각에 정리해보았당ㅎㅎ







오늘의 주저리

내가 어려워했던 클래스들을 계속 이용하는 문제들이 나와서 코딩을 해보는데에 시간이 좀 걸렸다. 그래도 여러 문제들을 풀어보니깐 자신감이 생겨난다..!! 코딩은 직접 부딪히고 오래 할수록 실력이 늘어나는게 눈에 보여서 기분이 좋다😍 이번주 마지막까지도 화이팅👊🏻👊🏻

profile
데이터 분석가(가 되고픈) 황성미입니다!
post-custom-banner

0개의 댓글