본문으로 건너뛰기

단원 1~8 섞어 풀기

파이썬 목차함수문제 12개

하루 지나 풀면 더 오래 남습니다. 1~8단원을 마친 다음 날 풀어 보세요. 1~8단원에서 골고루 12문제를 섞었고, 어느 레슨의 문제인지는 정답을 펼쳐야 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 리스트와 딕셔너리는 파이썬이 찍는 꼴 그대로(쉼표와 콜론 뒤 빈칸 · 작은따옴표) 씁니다. 줄 수를 알려 주지 않는 문제는 마지막 줄까지 다 씁니다. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.

한 번에 다 풀 필요는 없습니다. 열두 문제 모두 폰으로도 풀 수 있습니다(약 30~40분).

6번과 11번은 긴 코드입니다. 추적 표(줄 · 바뀐 이름 · 값 · 출력)를 그리며 따라가세요. 함수를 부르는 문제는 함수 칸마다 이름이 어느 값에 붙는지, 리스트에 이름이 둘 붙는 문제는 두 이름이 어느 리스트(①, ②)에 붙는지 이름표를 그리며 따라가면 덜 틀립니다. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.

문제 1

세 배를 돌려주는 함수에 입력받은 값을 넘깁니다. 2를 넣었습니다. 무엇이 찍힐까요? 넣은 값이 보이는 줄까지 세 줄을 글자 그대로 쓰세요.

def triple(x):
    return x * 3


n = input('수: ')
print(triple(n))
print(triple(int(n)))넣는 값2
힌트

5번 줄에서 n이 어떤 종류의 값에 붙는지 먼저 정하세요.

정답
실행 결과
수: 2
222
6
  • 5번 줄: 친 2로 글자 '2'가 만들어지고, n이 그 값에 붙습니다.
  • 6번 줄: triple 칸에서 x가 글자 '2'에 붙습니다. 글자에 * 3을 쓰면 세 번 되풀이해 '222'를 돌려줍니다.
  • 7번 줄: int(n)이 만든 수 2를 넘겨, 2 * 3인 6을 돌려받아 찍습니다.

흔한 오답은 둘째 줄의 6입니다. 입력받은 2가 수로 들어온다고 본 것입니다(문자열과 수를 가리지 않는 생각). input()은 늘 글자를 돌려주고, 글자에 *를 쓰면 곱하지 않고 되풀이합니다.

다시 볼 레슨: 입력은 늘 글자 · 문자열 잇기와 되풀이 · 매개변수와 인자

문제 2

무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

a = [1, 2]
b = a
b.append([3, 4])
a.extend([5])
print(a)
print(len(b))
힌트

줄마다 이름표를 그려 a와 b가 가리키는 리스트가 몇 개인지 보고, 3번 줄과 4번 줄이 각각 몇 칸을 더하는지 세어 보세요.

정답
실행 결과
[1, 2, [3, 4], 5]
4
줄리스트 ① — a와 b가 함께 가리킴
1·2[1, 2]
3[1, 2, [3, 4]]
4[1, 2, [3, 4], 5]

2번 줄 b = a는 새 리스트를 만들지 않고, a가 가리키는 리스트 ①에 이름 b를 하나 더 붙입니다(규칙 3). 3번 줄 append()는 받은 리스트 [3, 4]를 통째로 한 칸에 더하고, 4번 줄 extend()는 받은 리스트에서 값을 하나씩 꺼내 5를 더합니다. ①은 네 칸이라 len(b)는 4입니다.

  • 첫 줄을 [1, 2, 5], 둘째 줄을 3으로 쓰면 b가 사본을 받았다고 본 것입니다(복사된다는 생각). b = a는 같은 리스트에 이름을 하나 더 붙일 뿐입니다.
  • [1, 2, 3, 4, 5]와 5로 쓰면 append()도 값을 하나씩 꺼내 더한다고 본 것입니다. 하나씩 꺼내 더하는 것은 extend()이고, append()는 받은 값 하나를 한 칸에 더합니다.

다시 볼 레슨: 리스트와 이름 둘 · 리스트를 제자리에서 바꾸기

문제 3

앞 문제처럼 a와 b가 한 리스트에서 시작하는데, 이번에는 b를 다른 꼴로 늘립니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

a = [1, 2]
b = a
b = b + [3]
b.append(4)
print(a)
print(b)
힌트

3번 줄의 b + [3]이 무엇을 만드는지, 그 뒤 b가 어느 리스트에 붙는지 그려 보세요.

정답
실행 결과
[1, 2]
[1, 2, 3, 4]
  • 2번 줄: b가 a와 같은 리스트 ①에 붙습니다.
  • 3번 줄: b + [3]은 두 리스트를 이은 새 리스트 ② [1, 2, 3]을 만들고, b만 ②에 다시 붙입니다. a는 ①에 그대로 붙어 있습니다.
  • 4번 줄: b가 가리키는 ②의 끝에 4를 더합니다. ①은 그대로입니다.

흔한 오답은 두 줄 모두 [1, 2, 3, 4]로 쓰는 것입니다. b를 새 리스트에 다시 붙이면 a도 따라 옮겨 간다고 본 것입니다(따라 옮겨 간다는 생각). 다시 붙이기는 그 이름 하나만 옮기고 리스트를 바꾸지 않습니다(규칙 3). 앞 문제의 append()·extend()처럼 리스트를 제자리에서 바꿀 때만 다른 이름으로도 바뀐 것이 보입니다.

다시 볼 레슨: 리스트와 이름 둘 · 이름표 다시 붙이기

문제 4

주문이 끝나면 벨을 울리는 함수입니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.

def ring():
    print('딩동')


ring
print('주문 완료')
ring()
힌트

5번 줄과 7번 줄에서 ring 뒤에 무엇이 있는지 견주어 보세요.

정답

모두 2줄입니다.

실행 결과
주문 완료
딩동
  • 5번 줄: 이름 ring이 가리키는 함수를 꺼내기만 하고 부르지 않아, 아무 일도 일어나지 않습니다.
  • 6번 줄: 주문 완료를 찍습니다.
  • 7번 줄: 괄호를 붙여 부르니 새 칸이 생기고 2번 줄이 딩동을 찍습니다.

흔한 오답은 맨 위에 딩동이 한 줄 더 붙은 세 줄입니다. 괄호 없이 이름만 써도 함수가 실행된다고 본 것입니다(괄호 없이도 부른다는 생각). 함수를 부르는 것은 이름 뒤의 괄호입니다(규칙 5).

다시 볼 레슨: 함수 만들고 부르기

문제 5

주문을 받고 잔 수를 찍으려 합니다. 이 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

print('주문을 받습니다')
serve(2)


def serve(n):
    print(n, '잔')
  • ① 주문을 받습니다를 찍은 뒤 2번 줄에서 NameError로 멈춘다
  • ② 주문을 받습니다를 찍은 뒤 6번 줄이 2 잔을 찍고 끝난다
  • ③ 주문을 받습니다를 찍은 뒤 2번 줄만 건너뛰고 끝까지 간다
힌트

2번 줄을 실행하는 그때 이름 serve가 무엇에 붙어 있는지 보세요.

정답

① — 실행 결과는 이렇습니다.

실행 결과
주문을 받습니다Traceback (most recent call last):  File "main.py", line 2, in <module>    serve(2)    ^^^^^NameError: name 'serve' is not defined

위에서 아래로 한 줄씩 실행하므로(규칙 1), 2번 줄을 실행할 때는 5번 줄의 def가 아직 함수를 만들어 이름 serve를 붙이지 않았습니다. 그래서 serve라는 이름이 없다는 NameError로 멈춥니다. 1번 줄은 이미 실행되어 주문을 받습니다는 남습니다.

  • ② 파이썬이 def를 어디에 두든 먼저 읽어 둔다고 봤습니다. def 줄도 위에서 아래로 실행될 때 비로소 함수를 만들어 이름을 붙입니다. 부르는 줄을 함수 정의 아래로 옮기면 2 잔까지 찍힙니다.
  • ③ 오류가 난 줄만 건너뛴다고 봤습니다. 실행은 오류가 난 그 줄에서 멈춥니다(규칙 1).

다시 볼 레슨: 함수 만들고 부르기 · 오류 메시지 읽기

문제 6

문구점은 4,000원어치마다 쿠폰을 한 장 줍니다. 손님 넷이 3,000원짜리 공책을 차례로 1권, 2권, 3권, 4권 샀습니다. 쿠폰을 두 장 이상 받은 손님과 모두 준 쿠폰 수를 찍습니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.

def coupons(won):
    return won // 4000


total = 0
for books in range(1, 5):
    got = coupons(books * 3000)
    total = total + got
    if got > 1:
        print(books, got)
print('합계', total)
힌트

바퀴마다 books → coupons에 넘기는 값 → got → total → 9번 줄의 조건 차례로 추적 표에 적습니다.

정답

모두 3줄입니다.

실행 결과
3 2
4 3
합계 6

바퀴마다 한 줄로 줄인 추적 표입니다. 실행되는 줄마다 한 줄씩 쓰면 함수 칸의 2번 줄까지 26줄입니다.

books넘긴 값gottotalgot > 1출력
1300000False
2600011False
3900023True3 2
41200036True4 3
반복 뒤(11번 줄)6합계 6

7번 줄은 books * 3000을 먼저 계산한 값 하나를 넘기고, coupons 칸에서 won이 그 값에 붙어 4,000으로 나눈 몫을 돌려줍니다. range(1, 5)는 1, 2, 3, 4를 내줘 네 바퀴입니다. 10번 줄은 8칸이라 got > 1이 참일 때만 찍고, 11번 줄은 들여 쓰지 않아 반복이 끝난 뒤 한 번 찍습니다(규칙 4).

흔한 오답은 5 3과 합계 9까지 쓰는 것입니다. range(1, 5)에 끝 수 5도 든다고 본 것입니다(끝도 든다는 생각). 바퀴마다 1 0부터 4 3까지 네 줄을 찍는다고 쓰면 10번 줄이 if 덩어리 안이라는 것을 놓친 것입니다(들여쓰기는 꾸밈이라는 생각). 줄이 드는 덩어리는 들여쓰기 칸 수가 정합니다(규칙 4).

다시 볼 레슨: for와 range · 돌려받은 값 쓰기 · if와 else · 사칙 계산과 몫·나머지

문제 7

무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.

orders = ['커피', '라테']
count = len(orders)
orders.append('녹차')
print(count, len(orders))
힌트

2번 줄이 실행되는 그때 orders가 가리키는 리스트가 몇 칸인지 보세요.

정답
실행 결과
2 3
  • 2번 줄: 그때 리스트가 두 칸이라 len(orders)가 2로 계산되고, count가 2에 붙습니다.
  • 3번 줄: 리스트 끝에 '녹차'를 더해 세 칸이 됩니다. count는 다시 계산되지 않습니다.
  • 4번 줄: count는 2이고, 지금 다시 센 len(orders)는 3입니다.

흔한 오답은 3 3입니다. count가 len(orders)라는 식을 저장해 두었다가 찍을 때 다시 센다고 본 것입니다(식이 저장된다는 생각). =는 오른쪽을 그때 한 번 계산해 만든 값 하나에 이름을 붙입니다(규칙 2).

다시 볼 레슨: 변수: 값에 이름 붙이기 · 리스트와 이름 둘

문제 8

주문 번호를 알리는 함수 둘입니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.

def call(no):
    print(f'{no}번 나왔어요')


def ticket(no):
    return f'{no}번 나왔어요'


print(ticket(7))
print(call(8))
힌트

9번 줄과 10번 줄의 바깥 print가 각각 무엇을 넘겨받는지, 함수가 돌려준 값을 먼저 적어 보세요.

정답

모두 3줄입니다.

실행 결과
7번 나왔어요
8번 나왔어요
None
  • 9번 줄: ticket 칸에서 no가 7에 붙고, 6번 줄이 글자 '7번 나왔어요'를 돌려줍니다. 바깥 print가 그 값을 찍습니다.
  • 10번 줄: call 칸에서 2번 줄이 8번 나왔어요를 화면에 찍고, return이 없는 call은 None을 돌려줍니다. 바깥 print가 그 None을 찍습니다.

흔한 오답은 None을 빼고 두 줄만 쓰는 것입니다. call이 화면에 찍은 글자가 부른 자리로 돌아온다고 본 것입니다(찍는 것과 돌려주는 것이 같다는 생각). print는 화면에 쓰고 None을 돌려주며, 부른 자리로 값을 보내는 것은 return입니다(규칙 5).

다시 볼 레슨: 함수 만들고 부르기 · 매개변수와 인자

문제 9

택배 무게(kg)로 상자 크기를 정하는 함수입니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.

def box(kg):
    if kg >= 3:
        return '대'
    if kg >= 2:
        return '중'
    return '소'


print(box(3), box(2), box(1))
힌트

box(3)을 부를 때 3번 줄 다음에 실행되는 줄이 어디인지 보세요.

정답
실행 결과
대 중 소
부르기kg >= 3kg >= 2돌려준 값
box(3)True(보지 않음)'대'
box(2)FalseTrue'중'
box(1)FalseFalse'소'

return을 만나면 값을 돌려주며 함수가 그 자리에서 끝납니다. 그래서 box(3)은 3번 줄에서 끝나 4번 줄의 if를 보지 않고, box(2)는 5번 줄에서 끝납니다(규칙 5).

흔한 오답은 소 소 소입니다. return 뒤의 줄도 실행되어 마지막 6번 줄의 값이 돌아간다고 본 것입니다. return은 값을 돌려주며 함수를 끝내므로 그 뒤의 줄로 가지 않습니다(규칙 5).

다시 볼 레슨: 돌려받은 값 쓰기 · if와 else

문제 10

가장 싼 값을 돌려주는 함수 둘입니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

def low_new(prices):
    return sorted(prices)[0]


def low_sort(prices):
    prices.sort()
    return prices[0]


menu = [4500, 3500, 4000]
print(low_new(menu), menu)
print(low_sort(menu), menu)
힌트

함수를 부를 때마다 prices가 어느 리스트에 붙는지 그리고, 2번 줄과 6번 줄이 그 리스트를 바꾸는지 보세요.

정답
실행 결과
3500 [4500, 3500, 4000]
3500 [3500, 4000, 4500]
  • 11번 줄: low_new 칸에서 prices가 menu와 같은 리스트 ①에 붙습니다(규칙 3). 2번 줄 sorted(prices)는 정렬한 새 리스트 ②를 만들고, 그 0번 칸 3500을 돌려줍니다. ①은 그대로입니다.
  • 12번 줄: low_sort 칸에서 prices가 다시 ①에 붙고, 6번 줄 .sort()가 ①을 제자리에서 정렬합니다. 그래서 menu로 찍어도 정렬된 차례입니다.

흔한 오답은 둘째 줄의 3500 [4500, 3500, 4000]⁠입니다. 함수가 넘겨받은 리스트의 사본을 정렬한다고 본 것입니다(복사된다는 생각). 리스트를 넘기면 매개변수가 같은 리스트를 가리켜, .sort()가 바꾼 차례가 밖에서도 보입니다(규칙 3). 첫 줄의 리스트도 정렬된 차례로 쓰면 sorted()도 처음 리스트를 바꾼다고 본 것입니다. sorted()는 정렬한 새 리스트를 돌려줄 뿐입니다.

다시 볼 레슨: 리스트를 함수에 넘기면 · 정렬: sort와 sorted

문제 11

오늘 주문을 첫 글자로 적었습니다(라: 라테 · 커: 커피 · 취: 취소). 취소는 건너뛰고 메뉴마다 잔 수를 셉니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.

orders = '라라취커'
sold = {}
i = 0
while i < len(orders):
    ch = orders[i]
    i = i + 1
    if ch == '취':
        continue
    before = sold.get(ch, 0)
    sold[ch] = before + 1
print(sold)
힌트

바퀴마다 4번 줄의 조건 → ch → i → 7번 줄의 조건 → before → sold 차례로 추적 표에 적습니다.

정답
실행 결과
{'라': 2, '커': 1}

바퀴마다 한 줄로 줄인 추적 표입니다. 실행되는 줄마다 한 줄씩 쓰면 28줄입니다.

바퀴i < len(orders)chich == '취'beforesold
10 < 4 → True'라'1False0{'라': 1}
21 < 4 → True'라'2False1{'라': 2}
32 < 4 → True'취'3True → continue그대로
43 < 4 → True'커'4False0{'라': 2, '커': 1}
—4 < 4 → False반복 끝

셋째 바퀴의 continue는 그 바퀴의 남은 9·10번 줄만 건너뛰고 4번 줄로 돌아갑니다. i는 6번 줄에서 이미 3에 붙어 있어, 다음 바퀴는 넷째 글자부터 봅니다. 9번 줄의 get()은 키가 있으면 그 키의 값을, 처음 보는 키면 기본값 0을 돌려주고, 10번 줄이 1을 더한 값을 그 키와 한 쌍으로 담습니다.

흔한 오답은 {'라': 2}입니다. continue가 반복을 끝낸다고 본 것입니다. continue는 이번 바퀴의 남은 줄만 건너뜁니다. {'라': 1, '커': 1}로 쓰면 get()이 늘 기본값 0을 돌려준다고 본 것입니다. 기본값은 키가 없을 때만 돌아옵니다. 딕셔너리는 콜론과 쉼표 뒤에 빈칸을 넣고 키를 작은따옴표로 감싼 꼴로 찍힙니다.

다시 볼 레슨: break와 continue · while과 추적 표 · 세기: 메뉴별로 모으기

문제 12

인형 안에 작은 인형이 든 인형을 열고 닫습니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.

def doll(n):
    if n > 0:
        print('열기', n)
        doll(n - 1)
        print('닫기', n)


doll(2)
힌트

부를 때마다 칸을 하나씩 쌓아 그리고 칸마다 n을 적은 뒤, doll(0) 칸이 끝나면 실행이 어느 칸의 몇 번 줄로 가는지 보세요.

정답

모두 4줄입니다.

실행 결과
열기 2
열기 1
닫기 1
닫기 2

칸이 쌓이고 사라지는 차례대로 적은 표입니다.

차례칸그 칸의 n한 일출력
1doll(2)23번 줄, 4번 줄에서 doll(1) 부름열기 2
2doll(1)13번 줄, 4번 줄에서 doll(0) 부름열기 1
3doll(0)0n > 0이 거짓이라 바로 끝남
4doll(1)1돌아와 5번 줄닫기 1
5doll(2)2돌아와 5번 줄닫기 2

부를 때마다 새 칸이 쌓이고, 칸마다 n이 따로 붙습니다. doll(0)이 끝나면 자기를 부른 doll(1) 칸으로 돌아와 4번 줄 다음인 5번 줄을 실행하고, doll(1)이 끝나면 doll(2) 칸으로 돌아옵니다(규칙 5). 문제 11의 while은 한 칸에서 이름 i를 다시 붙여 가며 되풀이했지만, 재귀는 칸이 쌓였다가 하나씩 사라지며 돌아온 칸마다 자기 n으로 남은 줄을 실행합니다.

  • 닫기 0을 두 번 쓰면 n이 이름 하나라 0까지 줄어든다고 본 것입니다. 칸마다 n이 따로 있어, 돌아온 칸은 자기 칸의 n을 찍습니다(규칙 5).
  • 열기 2와 열기 1 두 줄만 쓰면 끝 조건에서 모두 끝난다고 본 것입니다. 끝난 칸은 자기를 부른 칸으로 돌아가 남은 줄을 실행합니다.
  • 닫기 2를 닫기 1보다 먼저 쓰면 돌아오는 차례가 부르는 차례와 같다고 본 것입니다. 가장 나중에 쌓인 칸이 가장 먼저 끝나고 돌아옵니다.

다시 볼 레슨: 재귀: 자기를 부르는 함수

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

파이썬 목차로