10단원 '파일과 모듈'의 다섯 레슨에서 여덟 문제를 내고, 앞 단원(반복과 패턴 · 함수 · 오류와 예외)에서 네 문제를 섞었습니다. 눈으로 코드를 따라가 무엇이 찍히는지 쓰거나, 빈칸을 채우고, 잘못된 줄을 고치거나, 짧은 프로그램을 직접 만듭니다.
한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 15분), 끝의 만들어 보기 둘은 컴퓨터에서 직접 돌려 봅니다. 이 단원을 건너뛰어도 되는지 보려면 문제 2·4·7·9를 먼저 풀어 보세요(약 6분). 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다. 모두 맞으면 11단원 첫 레슨 클래스와 객체로 넘어가고, 하나라도 틀리면 정답 끝에 적힌 '다시 볼 레슨'으로 돌아갑니다.
끝의 두 문제는 프로그램을 직접 만들어 봅니다. 아래 코드 칸에서 바로 고쳐 돌려 볼 수 있고, 내 컴퓨터에서 돌려 보는 길은 내 컴퓨터에서 돌려 보기에 있습니다. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.
문제 1
콜론(:)으로 이어진 문자열을 쪼갠 뒤 다시 하이픈(' - ')으로 이어 붙입니다. 무엇이 찍힐까요? 두 줄을 쓰세요.
s = '봄:여름:가을'
parts = s.split(':')
print(parts[0])
print(' - '.join(parts))
힌트
s.split(':')은 문자열을 ':' 자리마다 잘라 리스트 ['봄', '여름', '가을']을 돌려줍니다. parts[0]이 무엇인지, ' - '.join(parts)가 사이사이에 무엇을 끼워 넣는지 보세요.
정답
봄
봄 - 여름 - 가을- 2번 줄:
'봄:여름:가을'.split(':')이 리스트['봄', '여름', '가을']을 만들어parts에 붙입니다. - 3번 줄: 첫 번째 원소
parts[0]인'봄'을 찍습니다. - 4번 줄:
' - '.join(parts)가 리스트 원소 사이마다' - '를 끼워 넣은'봄 - 여름 - 가을'을 찍습니다.
흔한 오답은 마지막 '가을' 뒤에도 ' - '를 붙여 '봄 - 여름 - 가을 - '로 쓰는 것입니다. join()은 원소 사이에만 구분자를 넣습니다.
다시 볼 레슨: 글과 리스트 사이: split·join
문제 2
같은 파일 memo.txt를 'w' 모드와 'a' 모드로 차례로 열어 쓴 뒤 읽습니다. 무엇이 찍힐까요? 두 줄을 쓰세요.
with open('memo.txt', 'w') as f:
f.write('사과\n')
with open('memo.txt', 'w') as f:
f.write('배\n')
with open('memo.txt', 'a') as f:
f.write('감\n')
with open('memo.txt', 'r') as f:
print(f.read(), end='')
힌트
3번 줄에서 memo.txt를 다시 'w' 모드로 열 때, 1~2번 줄에서 써 두었던 '사과\n'가 어떻게 되는지 생각해 보세요.
정답
배
감- 1~2번 줄:
memo.txt를 새로 만들어'사과\n'를 씁니다. - 3~4번 줄: 다시
'w'(덮어쓰기) 모드로 여는 순간 기존'사과\n'가 지워지고'배\n'만 남습니다. - 5~6번 줄:
'a'(이어쓰기) 모드로 열어 기존'배\n'뒤에'감\n'를 덧붙입니다.
흔한 오답은 '사과', '배', '감' 세 줄이 모두 찍힌다고 쓰는 것입니다. 'w' 모드로 파일을 다시 열면 이전 내용이 통째로 사라집니다.
다시 볼 레슨: 파일에 쓰기
문제 3
다음 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.
nums = [10, 20, 30]
print(', '.join(nums))
- ①
10, 20, 30이 찍히고 끝난다 - ②
[10, 20, 30]이 찍히고 끝난다 - ③ 2번 줄에서
TypeError로 멈춘다 - ④ 2번 줄에서
AttributeError로 멈춘다
힌트
', '.join(...)에 넘기는 리스트의 원소들이 문자열(str)인지 정수(int)인지 확인해 보세요.
정답
③ — 실행 결과는 이렇습니다.
Traceback (most recent call last): File "main.py", line 2, in <module> print(', '.join(nums)) ~~~~~~~~~^^^^^^TypeError: sequence item 0: expected str instance, int found- ③ (정답):
join()은 리스트의 모든 원소가 문자열(str)이어야 합칠 수 있습니다. 정수10이 들어 있어TypeError로 멈춥니다. - ①
print()처럼join()도 정수를 알아서 문자열로 바꿔 준다고 봤습니다. 먼저[str(n) for n in nums]로 바꾼 뒤 합쳐야 합니다. - ④
AttributeError는nums.join(', ')처럼 리스트에.join()을 불렀을 때 납니다.
다시 볼 레슨: 글과 리스트 사이: split·join
문제 4
파일에 적힌 세 줄을 한 줄씩 읽어 쉼표 뒤의 숫자를 모두 더합니다. 무엇이 찍힐까요?
with open('item.txt', 'w') as f:
f.write('사과,1000\n')
f.write('배,2000\n')
f.write('감,1500\n')
total = 0
with open('item.txt', 'r') as f:
for line in f:
s = line.strip()
row = s.split(',')
total += int(row[1])
print(total)
힌트
8~9번 줄에서 line.strip()과 s.split(',')을 실행하면 첫 줄은 ['사과', '1000']이 됩니다. row[0]과 row[1] 가운데 어느 쪽이 가격인지 보세요.
정답
4500- 7~10번 줄: 바퀴마다 한 줄을 읽어 끝의
\n을 떼고(strip()), 쉼표로 쪼갠 뒤(split(',')) 두 번째 조각row[1]을 정수로 바꿔total에 더합니다. 1000 + 2000 + 1500이 모여4500이 찍힙니다.
다시 볼 레슨: 파일 읽어 모으기 · 글과 리스트 사이: split·join · 합 모으기와 세기
문제 5
math 모듈에서 올림(ceil)과 내림(floor) 함수를 가져다 씁니다. 무엇이 찍힐까요? 두 줄을 쓰세요.
import math
from math import floor
print(math.ceil(3.2))
print(floor(3.8))
힌트
math.ceil(3.2)는 3.2 이상인 가장 작은 정수를 돌려주고, floor(3.8)은 3.8 이하인 가장 큰 정수를 돌려줍니다.
정답
4
3- 1번 줄
import math로 모듈 전체를 가져왔으므로math.ceil(3.2)는4를 돌려줍니다. - 2번 줄
from math import floor로floor를 직접 꺼내 왔으므로 마침표 없이floor(3.8)로 불러3을 돌려줍니다.
흔한 오답은 반올림으로 생각하여 둘 다 3과 4로 거꾸로 쓰는 것입니다. ceil은 무조건 올림, floor는 무조건 내림입니다.
다시 볼 레슨: 모듈 불러 쓰기
문제 6
리스트의 세 과일을 파일 b에 한 줄에 하나씩 저장하려 했는데, 마지막 '감' 한 줄만 남았습니다. 왜 그런지 찾고, 세 줄이 모두 저장되도록 고쳐 쓰세요.
for x in ['사과', '배', '감']:
with open('b', 'w') as f:
f.write(x + '\n')
with open('b', 'r') as f:
print(f.read(), end='')
감힌트
2번 줄 with open('b', 'w') as f:가 for 반복문 안에 있으면 바퀴가 돌 때마다 파일에 무슨 일이 일어나는지 보세요.
정답
with open('b', 'w') as f: 줄을 for 반복문 바깥(위)으로 옮겨 파일을 한 번만 열고 그 안에서 세 번 f.write()를 부릅니다.
items = ['사과', '배', '감']
with open('b', 'w') as f:
for x in items:
f.write(x + '\n')
with open('b', 'r') as f:
print(f.read(), end='')사과
배
감고치기 전에는 바퀴마다 파일을 'w' 모드로 새로 열어 앞 바퀴에 쓴 줄을 지워 버렸기 때문에 마지막 바퀴의 '감'만 남았습니다.
다시 볼 레슨: 파일에 쓰기 · for와 range
문제 7
같은 폴더에 calc.py와 main.py 두 파일이 아래와 같이 있습니다. main.py를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.
print('calc 로드')
def triple(n):
return n * 3
from calc import triple
print(triple(4))
- ①
12한 줄만 찍힌다 - ②
calc 로드가 먼저 찍히고 다음 줄에12가 찍힌다 - ③
12가 먼저 찍히고 다음 줄에calc 로드가 찍힌다 - ④
from calc.py import triple로 적지 않아ModuleNotFoundError가 난다
힌트
파이썬이 1번 줄 from calc import triple을 만나는 순간 calc.py 파일을 어떻게 처리하는지, 그리고 import 문에 .py를 붙이는지 떠올려 보세요.
정답
② — 첫 줄에 calc 로드, 둘째 줄에 12가 찍힙니다.
- ② (정답): 1번 줄
from calc import triple을 실행할 때 파이썬이calc.py를 위에서부터 끝까지 한 번 실행하므로print('calc 로드')가 먼저 찍히고, 이어서main.py의print(triple(4))가12를 찍습니다. - ①
from calc import triple이triple함수만 골라 오므로calc.py의 다른 줄은 실행되지 않는다고 봤습니다. - ③
main.py가 끝난 뒤에야calc.py가 실행된다고 봤습니다. - ④
import문에는 파일 확장자.py를 적지 않습니다. 오히려.py를 붙이면 오류가 납니다.
다시 볼 레슨: 내 파일을 모듈로
문제 8
파일 a.txt를 만들어 두 번 연속 f.read()를 부른 뒤, 없는 파일 b.txt를 열려 합니다. 무엇이 찍힐까요? 세 줄을 쓰세요.
with open('a.txt', 'w') as f:
f.write('안녕\n')
with open('a.txt', 'r') as f:
print(len(f.read()))
print(len(f.read()))
try:
open('b.txt', 'r')
except FileNotFoundError:
print('b 없음')
힌트
'안녕\n'은 세 글자입니다. 4번 줄에서 끝까지 다 읽은 뒤 5번 줄에서 다시 f.read()를 부르면 무엇이 돌아오는지, 7번 줄에서 없는 파일을 'r'로 열면 어디로 가는지 보세요.
정답
3
0
b 없음- 4번 줄: 첫 번째
f.read()가'안녕\n'(3글자)을 끝까지 읽어 길이3을 찍습니다. - 5번 줄: 읽기 위치가 이미 파일 끝에 가 있으므로 두 번째
f.read()는 빈 문자열''(길이0)을 돌려줍니다. - 7~9번 줄: 없는 파일
'b.txt'를'r'로 열 때FileNotFoundError가 나except블록이'b 없음'을 찍습니다.
흔한 오답은 5번 줄에서도 똑같이 3이 찍힌다고 쓰는 것입니다. 한 번 끝까지 읽은 파일 객체는 자동으로 맨 앞으로 되감기지 않습니다.
다시 볼 레슨: 파일 읽어 모으기 · try와 except
문제 9
1부터 6 사이의 주사위 눈을 두 번 뽑으려 한 코드인데 5번 줄에서 AttributeError가 났습니다. 왜 오류가 났는지 찾고, 4~5번 줄을 어떻게 고쳐야 할지 쓰세요.
import random
random.seed(0)
random = random.randint(1, 6)
print(random.randint(1, 6))
Traceback (most recent call last): File "main.py", line 5, in <module> print(random.randint(1, 6)) ^^^^^^^^^^^^^^AttributeError: 'int' object has no attribute 'randint'힌트
4번 줄 random = random.randint(1, 6)이 실행된 뒤 이름 random이 모듈을 가리키는지 정수를 가리키는지 보세요(규칙 3).
정답
4번 줄에서 결과를 담는 변수 이름을 random이 아닌 다른 이름(예: first)으로 바꿉니다.
import random
random.seed(0)
first = random.randint(1, 6)
print(first)
print(random.randint(1, 6))4
44번 줄에서 변수 이름을 모듈 이름과 같은 random으로 지어, 이름 random이 모듈 대신 정수 4를 가리키게 되었습니다(규칙 3). 그래서 5번 줄이 정수 4에서 .randint를 찾다가 AttributeError로 멈췄습니다.
다시 볼 레슨: 모듈 불러 쓰기 · 변수: 값에 이름 붙이기
문제 10
같은 폴더에 있는 내 파일 price_util.py에서 sale 함수를 꺼내 오고, 표준 라이브러리 math 모듈에서 ceil 함수를 꺼내 와 둘 다 마침표 없이 부르려고 합니다. 빈칸 (가)와 (나)에 들어갈 말을 차례로 쓰세요.
from ___(가)___ import sale
___(나)___ math import ceil
print(sale(10000))
print(ceil(4.2))
힌트
(가)에는 파일 이름 price_util.py에서 확장자 .py를 뺀 모듈 이름을 쓰고, (나)에는 모듈 안에서 특정 이름만 꺼내 올 때 맨 앞에 쓰는 키워드를 씁니다.
정답
(가):price_util(나):from
흔한 오답은 (가)에 확장자까지 붙여 price_util.py라고 쓰거나, (나)에 import를 쓰는 것입니다. 모듈 안에서 특정 함수만 꺼내 올 때는 from 모듈이름 import 함수이름 꼴로 적습니다.
문제 11 (만들어 보기)
쉼표(,)로 이어진 숫자 문자열 line(예: '10,20,30')을 받아, 각 숫자를 정수로 바꾸어 모두 더한 값을 돌려주는 함수 sum_csv(line)을 만들어 봅니다. 뼈대의 마지막 줄이 이렇게 찍어야 합니다.
60
끝에 print(sum_csv('5,15')) 한 줄을 더해 한 번 더 부르면 이렇게 나와야 합니다.
60
20
아래 뼈대에서 마지막 줄은 그대로 두고, 주석 셋 아래를 채우세요.
def sum_csv(line):
# 1. 쉼표로 쪼개기
# 2. 정수로 바꿔 더하기
# 3. 합 돌려주기
print(sum_csv('10,20,30'))
처음 펼 때 약 6MB를 받습니다.
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
견줄 시험 값
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.
힌트
parts = line.split(',')으로 쪼갠 뒤, total = 0을 만들고 for p in parts: 안에서 total += int(p)로 더합니다.
정답
모범 답입니다.
def sum_csv(line):
# 1. 쉼표로 쪼개기
parts = line.split(',')
# 2. 정수로 바꿔 더하기
total = 0
for p in parts:
total += int(p)
# 3. 합 돌려주기
return total
print(sum_csv('10,20,30'))60- 다르게 써도 되는 곳:
for p in line.split(','):처럼 한 줄로 바로 순회해도 같습니다. - 흔한 오답:
int(p)로 바꾸지 않고 문자열끼리 더하면'102030'이 됩니다.line.split()처럼 인자를 비워 두면 쉼표 자리에서 쪼개지지 않고['10,20,30']한 덩어리가 되어int('10,20,30')에서ValueError가 납니다.
다시 볼 레슨: 글과 리스트 사이: split·join · 합 모으기와 세기 · 돌려받은 값 쓰기
문제 12 (만들어 보기)
이번에는 빈 데서 씁니다. 두 줄의 주문 입력('품목,가격')을 받아 o.txt 파일에 저장한 뒤, 다시 그 파일을 한 줄씩 읽어 품목 이름과 가격 합계를 찍는 프로그램을 만들어 봅니다.
input('첫째: ')과input('둘째: ')으로 두 줄을 입력받습니다.o.txt를'w'모드로 열어 두 줄을 각각 줄바꿈(\n)과 함께 저장합니다.o.txt를'r'모드로 열어 한 줄씩 읽으면서strip()과split(',')으로 품목 이름과 가격을 나눕니다.- 줄마다 품목 이름을 찍고, 마지막에
'합계:', total을 찍습니다.
'사과,1000'과 '배,2500'을 넣으면 이렇게 나와야 합니다.
첫째: 사과,1000
둘째: 배,2500
사과
배
합계: 3500
입력만 '우유,2000'과 '식빵,3000'으로 바꾸면 이렇게 나와야 합니다.
첫째: 우유,2000
둘째: 식빵,3000
우유
식빵
합계: 5000
# 1. 두 줄 입력받아 파일에 쓰기
# 2. 파일 읽어 품목 찍고 가격 더하기
# 3. 합계 찍기넣는 값사과,1000배,2500
처음 펼 때 약 6MB를 받습니다.
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
견줄 시험 값
input()마다 위에서부터 한 줄씩 들어갑니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 넣은 값 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.
힌트
a = input('첫째: ')와 b = input('둘째: ')를 받은 뒤 with open('o.txt', 'w') as f: 안에서 f.write(a + '\n')와 f.write(b + '\n')를 실행합니다. 이어서 with open('o.txt', 'r') as f:로 한 줄씩 읽으며 s = line.strip()과 row = s.split(',')으로 나눕니다.
정답
모범 답입니다.
a = input('첫째: ')
b = input('둘째: ')
with open('o.txt', 'w') as f:
f.write(a + '\n')
f.write(b + '\n')
total = 0
with open('o.txt', 'r') as f:
for line in f:
s = line.strip()
row = s.split(',')
print(row[0])
total += int(row[1])
print('합계:', total)넣는 값사과,1000배,2500첫째: 사과,1000
둘째: 배,2500
사과
배
합계: 3500- 다르게 써도 되는 곳:
s.split(',')의 결과를name, price = s.split(',')처럼 두 변수에 나누어 담아도 같습니다. - 흔한 오답:
f.write(a)처럼 끝에'\n'을 붙이지 않으면 두 입력이'사과,1000배,2500'한 줄로 붙어 저장됩니다.- 읽을 때 두 번째
with open('o.txt', 'r')대신'w'로 열면 방금 저장한 파일 내용이 지워집니다.
다시 볼 레슨: 파일에 쓰기 · 파일 읽어 모으기 · 글과 리스트 사이: split·join