하루 지나 풀면 더 오래 남습니다. 1~11단원을 마친 다음 날 풀어 보세요. 1~11단원에서 골고루 12문제를 섞었고, 어느 레슨의 문제인지는 정답을 펼쳐야 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 리스트와 딕셔너리는 파이썬이 찍는 꼴 그대로(쉼표와 콜론 뒤 빈칸 · 작은따옴표) 씁니다. 줄 수를 알려 주지 않는 문제는 마지막 줄까지 다 씁니다. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.
한 번에 다 풀 필요는 없습니다. 열두 문제 모두 폰으로도 풀 수 있습니다(약 30~40분).
이름표 그림(리스트 · 딕셔너리 · 객체 · 함수 칸)과 추적 표를 그리며 따라가면 덜 틀립니다. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.
문제 1
정수가 들어올 때까지 다시 묻는 코드입니다. 차례로 열과 4를 넣었습니다. 무엇이 찍힐까요? 넣은 값이 보이는 줄까지 세 줄을 글자 그대로 쓰세요.
while True:
s = input('수: ')
try:
n = int(s)
break
except ValueError:
print('숫자만!')
print(n * 10)넣는 값열4
힌트
첫 바퀴에서 int('열')이 어떤 예외를 내고 어디로 점프하는지, 둘째 바퀴에서 int('4') 뒤에 break가 무엇을 끝내는지 보세요.
정답
수: 열
숫자만!
수: 4
40- 첫 바퀴:
int('열')에서ValueError가 나 5번 줄break를 건너뛰고except블록으로 점프해숫자만!을 찍습니다(규칙 7). - 둘째 바퀴:
int('4')가 정수4를 만들어n에 붙이고, 5번 줄break가while반복을 끝냅니다. - 8번 줄:
4 * 10인40을 찍습니다.
다시 볼 레슨: 맞는 값이 올 때까지 다시 묻기 · try와 except · 입력은 늘 글자
문제 2
무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.
a = [1, 2]
b = a
c = a.copy()
b.append(3)
c.append(4)
print(a)
print(b)
print(c)
힌트
b = a가 새 리스트를 만드는지, c = a.copy()가 새 리스트를 만드는지 이름표를 그려 보세요.
정답
[1, 2, 3]
[1, 2, 3]
[1, 2, 4]b = a는a가 가리키는 리스트 ①에 이름표b만 하나 더 붙입니다(규칙 3). 따라서b.append(3)은 리스트 ①을 제자리에서 바꾸어a와b모두[1, 2, 3]이 됩니다.c = a.copy()는 새로 복제한 리스트 ②[1, 2]를 만들어c에 붙이므로c.append(4)는 리스트 ②만[1, 2, 4]로 바꿉니다.
다시 볼 레슨: 리스트 복사: copy와 이름 더 붙이기 · 리스트와 이름 둘
문제 3
쉼표로 이어진 주문 문자열을 쪼개 메뉴마다 몇 번 나왔는지 셉니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
line = '커피,라테,커피'
sold = {}
for m in line.split(','):
sold[m] = sold.get(m, 0) + 1
print(sold)
힌트
line.split(',')이 만든 리스트의 원소를 차례로 따라가며 sold.get(m, 0) + 1이 얼마가 되는지 세어 보세요.
정답
{'커피': 2, '라테': 1}line.split(',')은 ['커피', '라테', '커피']를 만듭니다. 처음 나온 메뉴는 sold.get(m, 0)이 0을 돌려주어 1이 저장되고, 다시 나올 때마다 1씩 더해져 '커피'는 2, '라테'는 1이 됩니다.
다시 볼 레슨: 글과 리스트 사이: split·join · 세기: 메뉴별로 모으기
문제 4
글자 수 기준으로 정렬하려 할 때 key=len과 key=len()의 차이를 묻습니다. 먼저 아래 코드의 출력을 한 줄로 쓰고, 만약 2번 줄을 print(sorted(w, key=len()))처럼 len 뒤에 빈 괄호를 붙여 쓰면 왜 오류가 나는지 고르세요.
w = ['카푸치노', '녹차', '라테']
print(sorted(w, key=len))
- ①
sorted()에는 내장 함수len을 쓸 수 없고lambda만 쓸 수 있어서 - ②
len()이 인자 없이 먼저 호출되어TypeError가 나서 - ③ 문자열 리스트에는
key를 쓸 수 없어서
힌트
key= 자리에는 정렬할 때마다 원소 하나씩 넣어 부를 함수 자체를 넘겨야 합니다. len()처럼 괄호를 붙이면 그 자리에서 인자 0개로 함수를 부른 셈이 됩니다.
정답
출력은 다음과 같고, 까닭은 ②입니다.
['녹차', '라테', '카푸치노']key=len은 함수 len 자체를 넘겨 주어 sorted()가 원소마다 len('카푸치노')(4), len('녹차')(2), len('라테')(2)를 불러 글자 수 순서대로 줄 세웁니다.
반면 key=len()이라고 적으면 sorted()를 부르기도 전에 len()을 인자 없이 먼저 호출하므로 인자가 부족하다는 TypeError 오류가 납니다.
다시 볼 레슨: 이름 없는 함수 lambda · 함수 만들고 부르기
문제 5
재귀 함수 f(n)을 부릅니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
def f(n):
if n <= 1:
return 1
return n + f(n - 2)
print(f(5))
힌트
f(5) → f(3) → f(1) 차례로 칸이 쌓였다가, f(1)이 돌려준 1부터 거슬러 올라오며 더해지는 값을 적어 보세요.
정답
9칸이 쌓였다가 값을 돌려주며 풀리는 차례입니다(규칙 5).
| 차례 | 칸 | 계산식 | 돌려주는 값 |
|---|---|---|---|
| 1 | f(5) | 5 + f(3) 대기 | |
| 2 | f(3) | 3 + f(1) 대기 | |
| 3 | f(1) | n <= 1이 참 | 1 |
| 4 | f(3) | 3 + 1 | 4 |
| 5 | f(5) | 5 + 4 | 9 |
흔한 오답은 끝 조건의 1만 돌아온다고 보아 1을 쓰거나, f(n - 1)로 착각해 15를 쓰는 것입니다. n - 2씩 줄어들므로 5 + 3 + 1 = 9가 돌아옵니다.
다시 볼 레슨: 재귀: 자기를 부르는 함수
문제 6
무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
a = [2, 5, 3, 8, 1]
b = [x * 2 for x in a if x >= 3]
print(b)
힌트
a에서 x >= 3을 만족하는 원소만 골라낸 뒤, 각 원소에 2를 곱한 새 리스트를 적어 보세요.
정답
[10, 6, 16]a에서 3 이상인 원소는 차례대로 5, 3, 8이고, 각각 2를 곱한 [10, 6, 16]이 만들어집니다.
다시 볼 레슨: 리스트 컴프리헨션 · 거르기와 바꿔 담기
문제 7
함수 안의 이름과 밖의 이름이 같을 때 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.
bonus = 10
def calc(pt):
bonus = 50
return pt + bonus
print(calc(100))
print(bonus)
힌트
5번 줄 bonus = 50이 바깥의 bonus를 바꾸는지, 아니면 calc 함수 칸 안에 새 이름을 만드는지 보세요(규칙 5).
정답
150
10calc(100)칸 안에서bonus = 50은 그 함수 칸 안의 지역 변수bonus를 새로 만들어50에 붙입니다(규칙 5). 따라서100 + 50인150을 돌려주고 함수 칸이 사라집니다.- 바깥의
bonus는 처음 붙여 둔10그대로이므로 둘째 줄에는10이 찍힙니다.
다시 볼 레슨: 함수 안의 이름, 밖의 이름 · 돌려받은 값 쓰기
문제 8
파일에 두 줄을 썼다가 다시 읽어 수량을 더합니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
with open('t.txt', 'w') as f:
f.write('커피,2\n')
f.write('쿠키,3\n')
cnt = 0
with open('t.txt', 'r') as f:
for line in f:
s = line.strip()
row = s.split(',')
cnt += int(row[1])
print(cnt)
힌트
각 줄을 strip()하고 split(',')으로 나누면 row[0]과 row[1]에 무엇이 들어가는지 보세요.
정답
5첫 줄에서 row는 ['커피', '2'], 둘째 줄에서 ['쿠키', '3']이 됩니다. int(row[1])을 차례로 더하므로 2 + 3 = 5가 찍힙니다.
다시 볼 레슨: 파일에 쓰기 · 파일 읽어 모으기 · 글과 리스트 사이: split·join
문제 9
리스트의 값으로 12를 나누며 결과를 모읍니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.
ans = []
for x in [3, 0, 4]:
try:
ans.append(12 // x)
except ZeroDivisionError:
print('0 건너뜀')
print(ans)
힌트
x가 0일 때 12 // 0에서 ZeroDivisionError가 나면 except 블록을 실행한 뒤 반복이 멈추는지 다음 원소 4로 이어지는지 보세요.
정답
모두 2줄입니다.
0 건너뜀
[4, 3]x = 3:12 // 3인4가ans에 추가됩니다.x = 0:12 // 0에서ZeroDivisionError가 나except블록이0 건너뜀을 찍고 예외가 처리되었으므로 다음 바퀴로 이어집니다(규칙 7).x = 4:12 // 4인3이ans에 추가되어 마지막에[4, 3]이 찍힙니다.
다시 볼 레슨: try와 except
문제 10
StampCard 객체와 이름표를 다룹니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
class StampCard:
def __init__(self):
self.n = 0
def add(self, k=1):
self.n += k
a = StampCard()
b = StampCard()
c = a
a.add(2)
b.add(5)
c.add(3)
print(a.n, b.n, c.n)
힌트
StampCard()는 두 번 불렸으니 객체는 두 개(①, ②)뿐이고, c = a는 객체 ①에 이름표 c를 하나 더 붙인 것입니다(규칙 3).
정답
5 5 5a와c는 같은 객체 ①을 가리키고,b는 객체 ②를 가리킵니다(규칙 3).a.add(2)와c.add(3)은 모두 객체 ①의.n을 올려2 + 3 = 5로 만듭니다.b.add(5)는 객체 ②의.n을5로 만듭니다.- 따라서
a.n,b.n,c.n은 모두5입니다.
문제 11
부모 클래스 Card와 자식 클래스 VipCard가 있습니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.
class Card:
def __init__(self, n):
self.n = n
def add(self):
self.n += 1
class VipCard(Card):
def __init__(self, n, b):
super().__init__(n)
self.n += b
def add(self):
self.n += 2
v = VipCard(1, 3)
v.add()
print(v.n)
힌트
VipCard(1, 3)을 만들 때 super().__init__(1)로 self.n이 1이 된 뒤 b인 3이 더해지고, 이어서 v.add()가 어느 클래스의 add를 부르는지 보세요.
정답
6VipCard(1, 3)을 부르면super().__init__(1)이self.n = 1을 만들고, 그다음 줄self.n += 3이 실행되어self.n이4가 됩니다.v.add()를 부르면 자식 클래스VipCard에서 오버라이딩한add가 실행되어2가 더해지므로6이 찍힙니다.
다시 볼 레슨: 상속 · __init__과 self
문제 12
하루 주문 기록 줄 리스트에서 잘못된 줄은 건너뛰고 정상 주문만 Counter 객체에 모읍니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.
class Counter:
def __init__(self):
self.total = 0
def add(self, n):
self.total += n
rows = ['커피,2', '녹차,열']
c = Counter()
for line in rows:
p = line.split(',')
try:
c.add(int(p[1]))
except ValueError:
print('건너뜀:', p[0])
print('합계:', c.total)
힌트
두 줄 '커피,2'와 '녹차,열'에서 int(p[1])이 각각 어떻게 되는지 따라가 보세요.
정답
모두 2줄입니다.
건너뜀: 녹차
합계: 2- 첫 줄
'커피,2':int('2')가 성공해c.add(2)로c.total이2가 됩니다. - 둘째 줄
'녹차,열':int('열')에서ValueError가 나c.add를 건너뛰고건너뜀: 녹차를 찍습니다. - 반복이 끝난 뒤
합계: 2를 찍습니다.
바로 다음 12단원에서는 이 구조(파일 읽기 → 잘못된 줄 건너뛰기 → 메뉴별로 모아 영수증 쓰기)를 함수들로 나누어 작은 프로그램 하나로 완성합니다.
다시 볼 레슨: 메서드 · 글과 리스트 사이: split·join · try와 except