본문으로 건너뛰기

단원 1~11 섞어 풀기

파이썬 목차클래스문제 12개

하루 지나 풀면 더 오래 남습니다. 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).

차례칸계산식돌려주는 값
1f(5)5 + f(3) 대기
2f(3)3 + f(1) 대기
3f(1)n <= 1이 참1
4f(3)3 + 14
5f(5)5 + 49

흔한 오답은 끝 조건의 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
10
  • calc(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 5
  • a와 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를 부르는지 보세요.

정답
실행 결과
6
  • VipCard(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

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

파이썬 목차로