앞 레슨에서 만든 프로그램은 파일의 모든 줄이 '커피,2'처럼 깔끔할 때만 돌아갑니다. 실제 파일에는 '녹차,열'처럼 수량 자리에 글자가 잘못 적힌 줄이 섞여 있을 수 있습니다. 이번 레슨에서는 잘못된 줄을 try로 건너뛰고 완성된 영수증을 summary.txt 파일로 저장해 프로그램을 마무리합니다.
함수 하나씩 만들고 확인하기와 try와 except, 파일에 쓰기를 먼저 읽어야 이해됩니다.
앞 레슨에서 완성한 코드 펼쳐 보기
def calc_total(sold, menu):
total = 0
for m, n in sold.items():
total += menu[m] * n
return total
def make_report(sold, t):
out = []
for m, n in sold.items():
s = f'{m}: {n}잔'
out.append(s)
out.append(f'합계: {t}원')
return '\n'.join(out)1잘못된 줄을 try로 건너뛰기
orders.txt에 '녹차,열' 한 줄이 섞여 들어왔을 때, int('열')에서 프로그램 전체가 멈추지 않고 그 줄만 건너뛰도록 load_orders 안의 숫자 변환 자리에 try ... except ValueError:를 두릅니다(규칙 7).
fn = 'orders.txt'
with open(fn, 'w') as f:
f.write('커피,2\n')
f.write('녹차,열\n')
f.write('라테,1\n')
f.write('쿠키,1\n')
def load_orders(path):
d = {}
with open(path, 'r') as f:
rows = f.readlines()
for line in rows:
s = line.strip()
m, q = s.split(',')
try:
n = int(q)
except ValueError:
print('건너뜀:', s)
continue
d[m] = d.get(m, 0) + n
return d
고친 load_orders를 바로 불러 확인해 봅니다.
sold = load_orders('orders.txt')
print(sold)
건너뜀: 녹차,열
{'커피': 2, '라테': 1, '쿠키': 1}둘째 줄 '녹차,열'에서는 int('열')이 ValueError를 내어 except 블록으로 점프하고, 건너뜀: 녹차,열을 찍은 뒤 continue로 다음 줄('라테,1')을 계속 읽습니다.
2결과를 summary.txt 파일로 저장하기
이제 앞 레슨의 calc_total과 make_report로 영수증 문자열을 만들고, summary.txt 파일에 'w' 모드로 저장합니다.
def calc_total(sold, menu):
total = 0
for m, n in sold.items():
total += menu[m] * n
return total
def make_report(sold, tot):
out = []
for m, n in sold.items():
s = f'{m}: {n}잔'
out.append(s)
out.append(f'합계: {tot}원')
return '\n'.join(out)
sold = {
'커피': 2,
'라테': 1,
'쿠키': 1,
}
menu = {
'커피': 4000,
'라테': 4500,
'쿠키': 2000,
}
tot = calc_total(sold, menu)
rep = make_report(sold, tot)
out = 'summary.txt'
with open(out, 'w') as f:
f.write(rep + '\n')
저장된 summary.txt 파일을 다시 열어 내용이 제대로 들어갔는지 확인합니다.
with open(out, 'r') as f:
print(f.read(), end='')
커피: 2잔
라테: 1잔
쿠키: 1잔
합계: 14500원파일에 저장된 summary.txt를 다시 읽어 찍어 보니 세 메뉴의 잔 수와 합계: 14500원이 깔끔하게 들어 있습니다.
그렇다면 만약 summary.txt를 'w' 대신 'a'(이어 쓰기) 모드로 열면, 이 프로그램을 오늘 두 번 실행했을 때 summary.txt 파일 안은 어떻게 될까요? 먼저 생각해 보세요.
생각 비교하기
'a' 모드는 기존 내용을 지우지 않고 파일 끝에 덧붙이므로, 똑같은 영수증 네 줄이 위아래로 두 번 포개져 8줄짜리 파일이 됩니다. 요약 결과 파일처럼 실행할 때마다 최신 결과 하나로 덮어써야 하는 파일은 'w' 모드로 엽니다.
자주 틀리는 곳
1. try 블록을 for 반복문 바깥에 둔다
틀린 생각: with open(...)이나 for line in f: 전체를 try 하나로 크게 감싸면 코드가 더 깔끔하다.
반복문 바깥에 try를 두면 첫 번째 잘못된 줄('녹차,열')에서 예외가 났을 때 반복문 밖의 except로 점프해 버리므로, 그 뒤에 남아 있는 정상 주문('라테,1', '쿠키,1')은 아예 읽지 못하고 끝납니다.
맞는 규칙: 잘못된 줄만 건너뛰고 다음 줄을 계속 읽으려면 try ... except를 for 반복문 안쪽에 두어야 합니다.
2. 결과 요약 파일을 'a' 모드로 연다
틀린 생각: 파일에 쓰는 것이니 'w'든 'a'든 결과는 같다.
'a' 모드는 프로그램을 다시 돌려 고칠 때마다 이전 실행 결과가 파일에 그대로 남아 뒤에 계속 쌓입니다.
맞는 규칙: 매번 새로 만드는 요약 결과 파일은 'w' 모드로 열어 이전 내용을 지우고 새로 씁니다.
확인 문제
1. 여러 줄을 읽는 for 반복문에서 잘못된 줄만 건너뛰고 나머지 줄은 끝까지 처리하려 합니다. try ... except ValueError:를 어디에 두어야 할까요?
- ①
for반복문 바깥에서for전체를 감싼다 - ②
for반복문 안쪽에서int(...)변환 줄을 감싼다
힌트
except 블록이 끝난 뒤 다음 바퀴(for의 다음 줄)가 이어서 돌려면 try가 반복문 안에 있어야 하는지 밖에 있어야 하는지 생각해 보세요.
정답
② for 반복문 안쪽에서 int(...) 변환 줄을 감싼다입니다. 반복문 안에 두어야 그 줄만 예외 처리하고 다음 바퀴로 넘어갈 수 있습니다.
2. 아래 코드가 실행되면 무엇이 출력될까요?
rows = ['10', '열', '20']
tot = 0
for s in rows:
try:
tot += int(s)
except ValueError:
print('패스:', s)
print('합계:', tot)
힌트
'10'과 '20'은 tot에 더해지고, '열'은 ValueError가 나 '패스: 열'을 찍습니다.
정답
패스: 열
합계: 30'열'만 건너뛰고 10 + 20 = 30이 더해져 합계: 30이 출력됩니다.
3. 요약 문자열 rep를 summary.txt 파일에 덮어쓰기 모드로 저장하려고 합니다. 빈칸을 채우세요.
fn = 'summary.txt'
rep = '합계: 14500원'
with open(fn, ___) as f:
f.write(rep + '\n')
힌트
새로 덮어쓰는 파일 열기 모드는 작은따옴표로 감싼 한 글자입니다.
정답
'w'입니다 (with open(fn, 'w') as f:).
아래 코드의 rows 리스트 끝에 '쿠키,3'을 더 추가해 실행해 보세요.
처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.
다음 걸음
첫 레슨에서 print('안녕하세요') 한 줄을 실행하던 자리에서 출발해 여기까지 왔습니다. 그사이 우리는 파이썬 코드를 읽고 쓰는 일곱 가지 실행 규칙을 모두 익혔습니다.
- 위에서 아래로 한 줄씩 실행된다(규칙 1).
=는 오른쪽을 먼저 계산해 그 값에 왼쪽 이름표를 붙인다(규칙 2).- **변수는 상자가 아니라 값에 붙는 이름표(화살표)**라서, 가변 객체를 제자리에서 바꾸면 같은 객체를 가리키는 다른 이름으로도 보인다(규칙 3).
- 들여쓰기 칸 수가 어느 블록에 속하는지를 결정한다(규칙 4).
- 함수를 부를 때마다 독립된 새 칸이 생기고 끝나면 사라진다(규칙 5).
- 메서드와 클래스는 객체 안에 속성과 동작을 함께 묶고
self로 자기 자신을 가리킨다. - **예외(
try / except)**를 만나면 남은 줄을 건너뛰고 일치하는except블록으로 점프한다(규칙 7).
이제 어디로 나아가면 좋을까요?
- 내 일상의 작은 문제 하나를 골라 3단계 함수로 나누어 보기: 가계부 CSV 정리, 단어장 퀴즈, 폴더 안 파일 이름 정리처럼 직접 쓸 작은 프로그램을 입력 · 처리 · 출력 세 함수로 나누고 하나씩 확인하며 만들어 보세요.
- 표준 라이브러리 더 넓히기: 10단원에서 맛본
math,random외에도 표 데이터를 다루는csv, 설정과 웹 데이터를 다루는json, 날짜를 계산하는datetime을 찾아 써 보세요. - 자격증 시험을 준비한다면: 정보처리기사 실기를 준비한다면 단원 34(Python 코드 읽기)로 이어 가면 됩니다.