✍🏻 12일 & 13일 공부 이야기.
open(), read(), write(), close()
open('파일 경로', 'w')
#'w' write 새로 쓰기(파일이 이미 있다면 덮어씌우므로 기존 내용이 사라짐)
#'a' append 기존 파일에 내용 추가(파일이 없다면 그냥 파일을 새로 생성하는 것임)
#'x' 쓰기 모드(파일이 있으면 에러가 발생하고, 없으면 파일을 새로 생성함)
#'r' read 읽기 모드(파일이 없으면 에러가 발생)
변수명 = open('파일 경로', 'w')
변수명.write("작성할 문자열 입력")
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
변수명 = open('파일 경로', 'w')
변수명2 = 변수명.write("작성할 문자열 입력")
print(f'변수명2 : {변수명2}') print(f'변수명2 : {변수명2}')
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
변수명 = open('파일 경로', 'r')
변수명2 = 변수명.read() #변수명2는 작성된 문자열.
print(f'변수명2 : {변수명2}')
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
예제
오늘 일정을 사용자에게 입력을 받아 날짜와 시간과 함께 일정을 메모장에 저장하는 프로그램을 완성해라.
오늘 일정 : 집 청소
메모장에 출력될 내용
[2023-07-12 11:46:29 AM] 집 청소
import time #시간 관련 모듈 임포트
lt = time.localtime() #time에서 반환한 현재 지역의 시간대의 값을 날짜와 시간 형태로 변환해줌
#원하는 포맷에 맞게 출력해주는 strftime
date_str = '[' + time.strftime('%Y-%m-%d %I:%M:%S %p') + '] '
today_schedule = input('오늘 일정 : ')
#파일 내용 쓰기
file = open('파일 경로', 'w')
file.write(date_str + today_schedule)
file.close()
#파일 내용 읽기
file = open('파일 경로', 'r') #파일 특성상 encoding = "인코딩할 방식" 을 적어줘야할 때도 있음
str = file.read()
print(f'str : {str}')
file.close()
이번 시간에 time 모듈에 대해 자세히 살펴보게 되었는데 문제에서 사용한 localtime()과 strftime()에 대한 링크도 첨부👀👀
+ 파일에 저장된 특정 문자열(=변경하고자하는 문자열)을 다른 문자열(=변경할 문자열)로 바꾸는 방법
변수명 = open('파일 경로', 'r')
변수명2 = 변수명.read()
print(f'변수명2 : {변수명2}')
#문자열 치환하기
변수명2.replace('변경하고자하는 문자열', '변경할 문자열')
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
이말고도 구글링을 해보니 사용할 수 있는 함수가 많은듯 보였다! 필요한 함수가 있다면 그 때마다 찾아서 사용하면 될 것 같다:)
파일을 open()했으면 반드시 close() 해주어야 하는데, with ~ as 문을 사용하면 이를 생략할 수 있다.
#1
변수명 = open('파일 경로', 'w')
변수명2 = 변수명.write("작성할 문자열 입력")
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
#2
변수명 = open('파일 경로', 'r')
print(변수명.read())
변수명.close() #파일을 열었을땐 반드시 닫아줘야함
이렇게 작성되었던 코드가 아래와 같이 바뀔 수 있다.
#1
with open('파일 경로', 'w') as 변수명:
변수명.write("작성할 문자열 입력")
#2
with open('파일 경로', 'r') as 변수명:
print(변수명.read())
리스트 또는 튜플 데이터를 파일에 쓰기 위한 함수이다.
한 줄씩 텍스트 파일로 작성하여 저장해주는 특징을 가지고 있다.
fruit = ['apple\n', 'orange\n', 'banana\n', 'melon\n']
url = '파일 폴더 경로'
for item in fruit: #리스트에 있는 요소 하나 하나를 입력해주기 위함
with open(url + '파일명.txt', 'a') as f:
f.write(item)
이렇게 for문
을 이용해서 작성했던 코드를 아래와 같이 writelines()
를 이용하면 간편하게 바뀐다.
fruit = ['apple\n', 'orange\n', 'banana\n', 'melon\n']
url = '파일 폴더 경로'
with open(url + '파일명.txt', 'a') as f:
f.writelines(fruit)
with ~ as 문
을 사용할 때, 파일 경로를 한 번에 다 써주어도 좋지만 위와 같이 폴더 경로명과 파일명을 +
로 묶어서 사용해 줄 수도 있다.
📄 파일명.txt
apple
orange
banana
melon
readlines()
는 파일의 모든 데이터를 읽어서 리스트 형태로 반환해주는데 한 줄씩 리스트로 반환되는 특징을 가지고 있다.
readline()
은 한 줄만 읽어서 문자열로 반환해주는데 "텍스트 파일 한 줄 내용과 공백 1줄('\n')"이 포함되어 출력된다.
예제
📄 파일.txt
apple
orange
banana
melon
위와 같은 파일.txt가 있다고 했을 때 파이썬에서 다음 파일을 읽어 리스트에 저장하는 프로그램을 완성해라.
url = '파일 폴더 경로'
with open(url + '파일.txt', 'r') as f:
data = f.readlines()
print(data)
💻 출력
['apple\n', 'orange\n', 'banana\n', 'melon\n']
만약, 파일의 내용을 한 줄씩 순차적으로 읽고 싶다면 readline()을 사용하면 된다.
url = '파일 폴더 경로'
with open(url + '파일.txt', 'r') as f:
data = f.readline()
#마지막 공백 한 줄을 없애고 파일 내용을 한 줄씩 출력하는 코드
while data: #이런 반복문을 사용하지 않게 되면 그냥 한 줄만 출력하고 끝나버림.
print(data, end = '')
data = f.readline()
#만약 이 과정을 하지 않고
# print(data)
# data = f.readline()
#를 바로 출력했다면
#apple
#
#orange
#
#banana
#
#melon
#
#이렇게 출력되었을 것이다.
💻 출력
apple
orange
banana
melon
data는 마지막 줄바꿈('\n')을 가지고 있어, end = '' 를 사용해 다음 출력할 내용을 바로 이어서 출력하게 해준다.
기초 문제 풀이에 이어 중급 문제 풀이로 넘어왔다. 이전보다 더 생각해야할 것들이 많아지고, 문제에서 더 깊게 파고들만한 것이 무엇이 있을까 고민하면서 강의를 듣다보니깐.. 시간이 많이 들었다ㅎㅎ. 그 중에서 흥미로웠던 질문 몇 가지만 정리해보는걸루✍🏻
다음과 같이 출력되는 단리/월복리 계산기 함수 프로그램을 완성해라
#숫자 천 단위마다 ',' 넣어주는 함수
def format_num(n):
return format(n, ',')
#단리(원금에 대해서만 이자를 계산하는 방법)
def single_rate_cal(m, t, r): #m : 예치금, t : 예치 기간, r : 연 이율
total_rate_money = 0 #이자 금액
#단리의 이자는 원금 * 연이율 * 예치 기간
#연 이율을 %로 입력받았기 때문에 계산시 0.01을 곱해준 후 계산해야함
total_rate_money = m * (r * 0.01) * t
total_money = m + total_rate_money # 총 수령액 = 원금 + 이자
return int(total_money)
#월복리(월 마다 생기는 원금에 붙은 이자의 이자까지 계산하는 방법)
def multi_rate_cal(m, t, r):#m : 예치금, t : 예치 기간, r : 연 이율
month = t * 12 #연으로 입력받은 예치 기간을 월로 바꿔줌
month_rate = (r / 12) * 0.01 #월복리의 이자는 1/12로 줄어드므로 이렇게 계산됨
total_money = m
for i in range(month):
total_money += total_money * month_rate #원금에 달마다 이자를 계산해서 더해줌
return int(total_money)
money = int(input("예치금(원) : "))
term = int(input("기간(년) : "))
rate = int(input("연 이율(%) : "))
print("\n")
print("[단리 계산기]")
print("================================")
print(f"예치금 : {format_num(money)}원")
print(f"예치기간 : {term}년")
print(f"연 이율 : {rate}%")
print("--------------------------------")
print(f"{term}년 후 총 수령액 : {format_num(single_rate_cal(money, term, rate))}원")
print("================================")
print("\n")
print("[월복리 계산기]")
print("================================")
print(f"예치금 : {format_num(money)}원")
print(f"예치기간 : {term}년")
print(f"연 이율 : {rate}%")
print("--------------------------------")
print(f"{term}년 후 총 수령액 : {format_num(multi_rate_cal(money, term, rate))}원")
print("================================")
💻 출력
파이썬에서 단리/복리 문제는 항상 나오는 것 같다.
복리에도 여러 종류가 있던데.. 문제 잘 읽자...!!
로또 모듈을 만들고 로또의 결과가 출력되는 프로그램을 완성해라
📄lotto.py
import random
user_nums = [] #사용자가 선택한 번호
rand_nums = [] #로또 번호(기계 random)
cor_nums = [] #로또 번호 중 사용자가 선택한 번호와 일치하는 번호
rand_bonus_num = 0 #보너스 번호
def setUserNums(ns):
global user_nums
user_nums = ns
# def getUserNums():
# return user_nums
def setRandNums():
global rand_nums
rand_nums = random.sample(range(1, 46), 6) #1부터 45까지의 숫자 중 랜덤으로 6개 선택
# def getRandNums():
# return rand_nums
def setBonusNum():
global rand_bonus_num
while True: #보너스 번호는 앞서 뽑은 6개의 번호 외의 번호로 선택됨.
rand_bonus_num = random.randint(1, 45) #1부터 45까지의 숫자 중 랜덤으로 1개 선택
if rand_bonus_num not in rand_nums:
break
def getBonusNum():
return rand_bonus_num
def lottoResult():
global user_nums
global rand_nums
global cor_nums
cor_nums = [] #일치하는 번호 개수를 구해 등수를 매김
for un in user_nums:
if un in rand_nums:
cor_nums.append(un) #사용자가 선택한 번호 중 로또 번호와 일치하는 번호가 있으면 cor_nums 리스트에 들어감
if len(cor_nums) == 6:
print("1등 당첨")
print(f'번호 : {cor_nums}')
elif len(cor_nums) == 5 and rand_bonus_num in user_nums:
print("2등 당첨")
print(f'번호 : {cor_nums}, 보너스 번호 : {rand_bonus_num}')
elif len(cor_nums) == 5:
print("3등 당첨")
print(f'번호 : {cor_nums}')
elif len(cor_nums) == 4:
print("4등 당첨")
print(f'번호 : {cor_nums}')
elif len(cor_nums) == 3:
print("5등 당첨")
print(f'번호 : {cor_nums}')
else:
print("아쉽습니다. 다음 기회에")
print(f"당첨 번호 : {rand_nums}")
print(f"보너스 번호 : {rand_bonus_num}")
print(f"선택 번호 : {user_nums}")
print(f"일치 번호 : {cor_nums}")
def num_rule():
while True:
can_use_num = int(input("번호(1~45) 입력 : "))
if can_use_num >=1 and can_use_num <= 45:
return can_use_num
break
print("로또 번호는 1부터 45까지입니다. 다시 입력해주세요.")
def startLotto():
#Step1. 사용자에게 번호 6개 선택 받기
##아래 주석처리된 부분은 강의에서 짠 코드
# n1 = int(input("번호(1~45) 입력 : "))
# n2 = int(input("번호(1~45) 입력 : "))
# n3 = int(input("번호(1~45) 입력 : "))
# n4 = int(input("번호(1~45) 입력 : "))
# n5 = int(input("번호(1~45) 입력 : "))
# n6 = int(input("번호(1~45) 입력 : "))
# user_select_nums = [n1, n2, n3, n4, n5, n6]
##위 코드대로 실행하다보니, 45를 초과하는 번호를 넣어도 그대로 넘어가길래
##num_rule()을 추가해 1부터 45까지의 숫자만 입력할 수 있고
##그 외의 숫자들은 안내문구 이후 다시 입력할 수 있도록 도와주는 프로그램으로 보완하였다.
user_select_nums = []
for cnt in range(6):
n = num_rule()
user_select_nums.append(n)
print("\n")
print("=================================")
#Step2. 사용자가 선택한 번호와 램덤으로 선택된 로또 번호를 비교해서 결과 출력하기
setUserNums(user_select_nums) #사용자가 선택한 번호를 넣어주고
setRandNums() #기계로 로또 번호를 뽑고
setBonusNum() #보너스 번호를 뽑고
lottoResult() #결과 출력하기
print("=================================")
📄lottostart.py
#실행 파일
import lotto as lt
lt.startLotto()
지난 시간에 배운 global 키워드
를 활용한 문제라 넣어봤다!
모듈은 기능을 하는 파일과 실행하는 파일 따로 만드는게 핵심이라고 하셨다. (메모메모)
강의에서 알려주신 내용에
로또 번호를 1부터 45까지만 입력받고, 만약 사용자가 1 ~ 45 외의 숫자를 입력할 시 다시 입력받게 하는 기능(num_rule() 모듈
) 을 추가하여 n1, n2 .. 이렇게 입력받는 것이 아닌 for문
을 사용했다.
수입과 공과금을 입력하면 공과금 총액과 수입 대비 공과금 비율을 계산하는 프로그램을 완성해라
원래는 하나의 데이터들에 대해서만 수입 대비 공과금(수도요금, 전기요금, 가스요금) 비율을 계산하는 문제인데, 강사님이 이 문제를 <전월대비, 전년대비>의 문제로 변형시킬 수 있다고 하셔서 두 년도의 데이터를 비교하는 프로그램을 완성시켜보았다.
📄utilityBill.py
income = 0
waterPrice = 0
electricPrice = 0
gasPrice = 0
def format_num(n):
return format(int(n) , ',')
# #수입 입력
# def setIncome(ic):
# global income
# income = ic
def getIncome(income):
return income
#
# #수도 요금 입력
# def setWaterPrice(wp):
# global waterPrice
# waterPrice = wp
# def getWaterPrice():
# return waterPrice
#
# #전기 요금 입력
# def setElectricPrice(ep):
# global electricPrice
# electricPrice = ep
# def getElectricPrice():
# return electricPrice
#
# #가스 요금 입력
# def setGasPrice(gp):
# global gasPrice
# gasPrice = gp
# def getGasPrice():
# return gasPrice
#공과금 계산 모듈
def getUtilityBill(waterPrice,electricPrice, gasPrice):
total = waterPrice + electricPrice + gasPrice
return total
#수입 대비 공과금 비율 계산 모듈
def getUtilityBillRate(waterPrice,electricPrice,gasPrice, income):
rate = getUtilityBill(waterPrice,electricPrice, gasPrice) / getIncome(income) * 100
return rate
#두 년도 수입 대비 공과금 비율 계산 모듈
def getUtilityBillRateYear(bill1, bill2, income1, income2):
rate = (bill1 / income1) / (bill2 / income2) * 100
return rate
#어떤 년도가 더 빠른지 계산
def getYear1(y1, y2):
if y1 > y2:
return y2
else:
return y1
#어떤 년도가 더 늦은지 계산
def getYear2(y1, y2):
if y1 < y2:
return y2
else:
return y1
📄utilityBillStart.py
import utilityBill as ub
print("안녕하세요. 저는 입력하신 두 년도의 수입 및 공과금의 비율을 계산해주는 프로그램입니다.")
#print("데이터를 모두 입력하시면 저는 최근 년도 대비 이전 년도의 수입 대비 공과금의 비율도 계산해줍니다.")
print("데이터를 차례로 입력해주세요!")
print('\n')
#두 년도를 계산한다고 했을 때, 년도와 데이터가 일치해야했었다.
#그냥 년도를 입력하고 차례로 요금 데이터를 입력받아도 되었지만,
#사용자가 무조건 이전 년도의 데이터부터 입력한다는 보장도 없고
#사용자가 어떻게 데이터를 입력해도 나는 <이전 년도 대비 최근 년도의 수입 대비 공과금의 비율>을 보여주고 싶었기 때문에
#딕셔너리 형태로 데이터들을 저장하고
#년도 비교를 통해 이전 년도의 데이터임을 알아차릴 수 있는 모듈을 사용하기로 했다.(getYear1() 모듈)
data_dic = {} #key : 년도 , value : [수입, 수도요금, 전기요금, 가스요금] 을 넣을 딕셔너리
#첫번째 데이터 입력
year1 = int(input('해당 데이터의 연도 입력 : '))
inputIncome1 = int(input(f"{year1}년의 수입 입력 : "))
inputWaterPrice1 = int(input(f"{year1}년의 수도요금 입력 : "))
inputElectricPrice1 = int(input(f"{year1}년의 전기요금 입력 : "))
inputGasPrice1 = int(input(f"{year1}년의 가스요금 입력 : "))
data_dic[f'{year1}'] = [inputIncome1, inputWaterPrice1, inputElectricPrice1, inputGasPrice1]
#원래 강의에서는 setIncome(inputIncome1)을 통해 데이터를 설정했었는데
#굳이 필요한가 싶어서 바로 딕셔너리에 집어넣어줬다.
#처음엔 setIncome(inputIncome1)가 None으로 출력되어 오류가 나서 그냥 변수 그대로 사용한 것도 있는데
#해당 모듈에 return이 없어서 None이 뜬 게 아닌가 싶다!!
#(-> setIncome과 getIncome 모듈을 만드신 이유에 대해 강사님께 여쭤보기!)
print('\n')
#두번째 데이터 입력
year2 = int(input('해당 데이터의 연도 입력 : '))
inputIncome2 = int(input(f"{year2}년의 수입 입력 : "))
inputWaterPrice2 = int(input(f"{year2}년의 수도요금 입력 : "))
inputElectricPrice2 = int(input(f"{year2}년의 전기요금 입력 : "))
inputGasPrice2 = int(input(f"{year2}년의 가스요금 입력 : "))
data_dic[f'{year2}'] = [inputIncome2, inputWaterPrice2, inputElectricPrice2, inputGasPrice2]
print("\n")
print("=======================================")
#두 년도의 데이터 중 이전 데이터를 먼저 출력
print(f'{ub.getYear1(year1, year2)}년의 데이터입니다.')
for key, value in data_dic.items():
if int(key) == ub.getYear1(year1, year2):
income1 = value[0]
print(f'{ub.getYear1(year1, year2)}년의 수입 : {ub.format_num(income1)}원')
utiliyBill1 = ub.getUtilityBill(value[1], value[2], value[3])
print(f'{ub.getYear1(year1, year2)}년의 공과금 : {ub.format_num(utiliyBill1)}원')
print(f'수입 대비 공과금 비율 : {ub.format_num(ub.getUtilityBillRate(value[1], value[2], value[3], value[0]))}%')
print("---------------------------------------")
#두 년도의 데이터 중 가장 최신의 데이터 출력
print(f'{ub.getYear2(year1, year2)}년의 데이터입니다.')
for key, value in data_dic.items():
if int(key) == ub.getYear2(year1, year2):
income2 = value[0]
print(f'{ub.getYear2(year1, year2)}년의 수입 : {ub.format_num(income2)}원')
utiliyBill2 = ub.getUtilityBill(value[1], value[2], value[3])
print(f'{ub.getYear2(year1, year2)}년의 공과금 : {ub.format_num(utiliyBill2)}원')
print(f'수입 대비 공과금 비율 : {ub.format_num(ub.getUtilityBillRate(value[1], value[2], value[3], value[0]))}%')
print("---------------------------------------")
#두 년도 대비 수입 대비 공과금 비율 출력
print(f'{ub.getYear1(year1, year2)}년 대비 {ub.getYear2(year1, year2)}년의 수입 대비 공과금 비율 : {round(ub.getUtilityBillRateYear(utiliyBill2,utiliyBill1,income2 , income1), 3)}%')
#관리를 잘 했는지, 부족했는지도 출력
if ub.getUtilityBillRateYear(utiliyBill2,utiliyBill1,income2 , income1) < 100:
print(f'{ub.getYear1(year1, year2)}년 대비 {ub.getYear2(year1, year2)}년에 관리를 더 잘하셨네요!!')
elif ub.getUtilityBillRateYear(utiliyBill2,utiliyBill1,income2 , income1) == 100:
print(f'{ub.getYear1(year1, year2)}년 대비 {ub.getYear2(year1, year2)}년의 비율이 같아요.')
else:
print(f'{ub.getYear1(year1, year2)}년 대비 {ub.getYear2(year1, year2)}년에 관리가 좀 부족했던 것 같아요ㅠㅠ')
print("=======================================")
💻 출력
앞선 문제와 달리.. 실행 파일이 좀 길어졌다ㅎㅎ..
두 년도의 수입 대비 공과금의 비율을 출력하고 싶어서 이렇게 길어지게 되었는데,
□ 사용자에게 연도를 입력받고, 수입, 공과금을 이어서 입력받을 것(-> 연도에 맞는 수입, 공과금의 데이터가 쌓여야함!)
□ 2. 두 년도의 데이터 중 이전 데이터, 최근 데이터 순으로 사용자에게 입력된 데이터들을 출력할 것(-> 두 년도 중 이전, 최근의 데이터가 무엇인지 알 수 있어야함!)
□ 3. 이전 년도 대비 최근 년도의 수입 대비 공과금의 비율을 계산하고, 최근 년도의 관리가 잘 되었는지, 못 되었는지 출력할 것.
이러한 기능들을 가진 프로그램을 만들고 싶었기에 데이터들을 보관, 비교하기에 딕셔너리 타입이 적합하다고 판단했다.
핵심은 getYear1()
모듈과 getYear2()
모듈의 값과 일치하는 딕셔너리 키에 해당하는 값들을 출력해주는 것이었다.
자세한 내용은 프로그램 주석 처리 해두었다:)
오늘은 파일 입출력에 대해 배워보고 함수와 모듈의 문제 풀이를 해보았다! 제일 시간이 좀 걸렸던 문제는 역시나 마지막 문제였었다. 강사님의 말씀을 듣고 '한 번 변형해볼까?'하는 마음은 비교적 쉽게 들었던 반면, 막상 생각한 구상을 코드로 옮기기까지의 과정이 복잡했었다. 어떤 변수들과 모듈이 필요하며, 그 변수들은 어떤 타입이 좋을 것인지, 코드를 실행시키다가 생각지도 못한 에러를 마주하는 것까지..ㅋㅋㅋ
제일 힘든게.. 어디서 발생한 에러인지 모르는 것, 해당 에러를 고치려 코드를 수정했는데 계에속 똑같은 에러가 뜨는 것, 더이상 이 세상이 알려준 모든 방법을 해본 것 같운데도 코드가 실행이 안 되는 것, 수정하다보면 아예 코드를 싹 바꿔야하나,,? 라는 생각이 드는..것 등이 있다. 그래도 내가 점점 해결해나가며 코드가 실행되고, 빨간줄이 사라지게 만들 수 있다는 것이 큰 성취감을 준다...! 어디서부터 시작해야될지도 모르겠는 막막함 속에서 하나 둘 내가 할 수 있는 길을 찾고 그걸 해나가는 과정이 좋다.🥰🥰
여러분은 프로그래밍이 어떤 이유 때문에 좋으신가요??