본문으로 건너뛰기

거르기와 바꿔 담기

파이썬 목차리스트와 튜플레슨 28 / 59

목차

거르기는 빈 리스트를 하나 두고, 값을 하나씩 꺼내 조건에 맞는 것만 그 리스트에 담는 틀입니다. 바꿔 담기는 꺼낸 값을 바꿔서 담는 같은 틀입니다.

가격 가운데 4000원 넘는 것만 고르거나, 모든 가격을 500원씩 올린 새 가격표를 만들 때가 있습니다. 원래 리스트에서 값을 지우거나 칸을 고치면 처음 리스트가 사라집니다. 거르기와 바꿔 담기는 원래 리스트를 그대로 두고, 고른 값이나 바꾼 값을 새 리스트에 담습니다. 이 레슨은 거르기와 바꿔 담기 코드를 직접 쓰는 틀 레슨입니다. 풀이 예제를 하위 목표 셋으로 나눠 읽고, 빈칸을 채우며 쓰기로 넘어갑니다.

12단계 중 1단계. 가격 가운데 4000원보다 비싼 값만 새 리스트에 담습니다.

1거르기의 세 하위 목표

가격 가운데 4000원보다 비싼 값만 고르는 풀이 예제이고, 그림의 코드입니다.

prices = [4000, 4500, 3500]
# 1. 빈 리스트
picked = []
# 2. 하나씩 꺼내 (맞으면) 담기
for price in prices:
    if price > 4000:
        picked.append(price)
# 3. 끝나고 쓰기
print(picked)
실행 결과
[4500]
  • 1. 빈 리스트: 3번 줄이 칸이 없는 새 리스트 ②를 만들고 이름 picked를 붙입니다. 아직 아무것도 고르지 않았습니다.
  • 2. 하나씩 꺼내 (맞으면) 담기: 5번 줄이 가격을 하나씩 꺼내 price를 붙이고, 6번 줄의 조건이 True일 때만 7번 줄이 그 값을 picked 끝에 더합니다.
  • 3. 끝나고 쓰기: 반복이 다 끝난 뒤 담은 리스트를 한 번 찍습니다.
줄바뀐 이름값출력
1prices① [4000, 4500, 3500]
3picked② []
5price4000
6조건 price > 4000False
5price4500
6조건 price > 4000True
7picked② [4500]
5price3500
6조건 price > 4000False
5꺼낼 수 없음 — 반복 끝
9[4500]

7번 줄 append()는 이름을 다시 붙이지 않고 리스트 ②를 제자리에서 바꿉니다. 이런 줄도 바뀐 이름 칸에 그 이름을, 값 칸에 바뀐 리스트를 적습니다. 꼬리표가 ② 그대로라 새 리스트가 아니라 같은 리스트입니다. picked처럼 고른 값을 모아 담는 이름을 담는 그릇이라고 부릅니다. 원래 리스트 ①은 처음 그대로입니다.

2바꿔 담기

모든 가격을 500원씩 올린 새 가격표를 만듭니다. 모든 값을 담으니 조건이 없고, 2번 하위 목표는 '하나씩 꺼내 담기'입니다.

prices = [4000, 4500, 3500]
# 1. 빈 리스트
raised = []
# 2. 하나씩 꺼내 담기
for price in prices:
    raised.append(price + 500)
# 3. 끝나고 쓰기
print(raised)
print(prices)
실행 결과
[4500, 5000, 4000]
[4000, 4500, 3500]

6번 줄은 price + 500을 먼저 계산한 새 값을 raised 끝에 더합니다. 바뀐 가격은 새 리스트에 담기고, 원래 prices는 그대로입니다.

3빈 리스트는 어디에 두는가

빈 리스트를 만드는 줄을 반복 안으로 옮겼습니다. 조건 price > 3000은 세 값 모두 True입니다. 무엇이 찍힐까요?

prices = [4000, 4500, 3500]
for price in prices:
    picked = []
    if price > 3000:
        picked.append(price)
print(picked)
실행 결과 보기
실행 결과
[3500]

예상과 다르면 그곳이 배울 곳입니다. 3번 줄은 덩어리 안에 있어 바퀴마다 실행됩니다. 바퀴마다 새 빈 리스트를 만들어 picked를 그 리스트에 다시 붙이니, 앞 바퀴에 담은 값은 아무도 가리키지 않는 리스트에 남고 마지막 바퀴의 3500만 남습니다(규칙 3·4). 1번 하위 목표 '빈 리스트'는 반복 앞에 한 번 둡니다.

예제

수를 돌리면

리스트 대신 수를 for에 넘겼습니다.

count = 3
for n in count:
    print(n)
실행 결과
Traceback (most recent call last):  File "main.py", line 2, in <module>    for n in count:             ^^^^^TypeError: 'int' object is not iterable

맨 아래 줄은 'int(정수)는 하나씩 꺼낼 수 있는 값이 아니다'라는 뜻입니다. for는 리스트·문자열·range()처럼 값을 차례로 내주는 것만 돕니다. 수만큼 돌려면 for n in range(count):⁠처럼 range()에 넘깁니다.

자주 틀리는 곳

틀린 생각: 리스트를 도는 중에 그 리스트에서 값을 지워도 남은 값을 다 본다.

돌면서 '커피'를 만날 때마다 지우면 '커피'가 다 사라질 것 같지만, 하나가 남습니다.

orders = ['커피', '커피', '라테']
for item in orders:
    if item == '커피':
        orders.remove(item)
print(orders)
실행 결과
['커피', '라테']

for는 리스트의 칸을 0번, 1번, 2번 차례로 꺼냅니다. 0번 '커피'를 지우면 뒤 칸이 한 칸씩 앞으로 와서 둘째 '커피'가 0번 자리로 갑니다. 다음 바퀴는 1번 칸 '라테'를 꺼내므로 둘째 '커피'를 건너뜁니다.

맞는 규칙: 도는 리스트에서 값을 지우면 뒤 칸이 당겨져 다음 값을 건너뜁니다. 거를 때는 원래 리스트를 그대로 두고 남길 값을 새 리스트에 담습니다.

틀린 생각: 빈 리스트를 만드는 줄은 반복 안에 둬도 담은 값이 쌓인다.

처음에 한 번 만드는 리스트라 어디에 두든 같아 보이지만, 덩어리 안의 줄은 바퀴마다 실행됩니다.

for n in [1, 2, 3]:
    picked = []
    picked.append(n)
print(picked)
실행 결과
[3]

맞는 규칙: 덩어리 안에서 picked = []를 쓰면 바퀴마다 새 빈 리스트에 다시 붙어 앞에서 담은 값이 사라집니다. 1번 하위 목표 '빈 리스트'는 반복 앞에 한 번 둡니다(규칙 4).

확인 문제

1. 1절 풀이 예제의 6번 줄을 if price > 4500:으로 바꿨습니다. 무엇이 찍힐까요?

prices = [4000, 4500, 3500]
# 1. 빈 리스트
picked = []
# 2. 하나씩 꺼내 (맞으면) 담기
for price in prices:
    if price > 4500:
        picked.append(price)
# 3. 끝나고 쓰기
print(picked)
힌트

바퀴마다 6번 줄 조건의 값을 추적 표에 적어 봅니다.

정답
실행 결과
[]

세 값 모두 4500보다 크지 않아 7번 줄이 한 번도 실행되지 않습니다. 아무것도 담지 않은 빈 리스트는 []로 찍힙니다.

흔한 오답은 [4500]입니다. 같은 값도 담는다고 본 것입니다. > 연산자는 두 값이 같으면 False입니다.

2. 빈칸을 채워 코드를 완성하세요.

(가) 4000원보다 싼 값만 담아 [3500]이 찍히도록 한 줄의 빈칸을 채우세요.

prices = [4000, 4500, 3500]
# 1. 빈 리스트
cheap = []
# 2. 하나씩 꺼내 (맞으면) 담기
for price in prices:
    if price < 4000:
        ________
# 3. 끝나고 쓰기
print(cheap)
힌트

2번 하위 목표 '하나씩 꺼내 (맞으면) 담기'에서 담는 줄입니다.

정답

cheap.append(price)입니다.

prices = [4000, 4500, 3500]
# 1. 빈 리스트
cheap = []
# 2. 하나씩 꺼내 (맞으면) 담기
for price in prices:
    if price < 4000:
        cheap.append(price)
# 3. 끝나고 쓰기
print(cheap)
실행 결과
[3500]

다르게 써도 되는 곳: cheap.extend([price])⁠나 cheap = cheap + [price]⁠도 [3500]이 찍힙니다. 빈칸에 cheap.append(3500)을 써도 같지만, 가격을 바꾸면 따라 바뀌지 않습니다.

흔한 오답은 cheap = cheap.append(price)⁠입니다. append()가 돌려준 None에 cheap을 다시 붙여 None이 찍힙니다. append()가 늘린 리스트를 돌려준다고 본 것입니다.

(나) 주문 가운데 '커피'만 골라 담습니다. 2번 하위 목표를 통째로 채우세요. 다 채운 코드는 ['커피', '커피']를 찍어야 하고, 1번 줄을 items = ['녹차', '커피']로 바꾸면 ['커피']를 찍어야 합니다.

items = ['커피', '라테', '커피']
# 1. 빈 리스트
coffee = []
# 2. 하나씩 꺼내 (맞으면) 담기

# 3. 끝나고 쓰기
print(coffee)
힌트

1절 풀이 예제의 2번 하위 목표와 같은 세 줄입니다. 조건은 꺼낸 값이 '커피'와 같은지입니다.

정답
items = ['커피', '라테', '커피']
# 1. 빈 리스트
coffee = []
# 2. 하나씩 꺼내 (맞으면) 담기
for item in items:
    if item == '커피':
        coffee.append(item)
# 3. 끝나고 쓰기
print(coffee)
실행 결과
['커피', '커피']

다르게 써도 되는 곳: 꺼낸 값의 이름은 item 말고 다른 낱말로 지어도 됩니다. 7번 줄은 coffee.append('커피')로 써도 두 시험 값 모두 같습니다.

흔한 오답은 if 줄 없이 모두 담는 것입니다. 그러면 ['커피', '라테', '커피']가 찍히고, 둘째 시험 값에서도 ['녹차', '커피']가 찍힙니다. 조건 없이 담기만 해도 '커피'만 골라진다고 본 것입니다.

3. 시험 점수마다 5점씩 더하려고 쓴 코드입니다. 무엇이 찍힐까요?

scores = [70, 85, 90]
for score in scores:
    score = score + 5
print(scores)
힌트

바퀴마다 3번 줄 뒤에 이름 score와 리스트 scores의 칸이 각각 무엇을 가리키는지 이름표로 그려 봅니다.

정답
실행 결과
[70, 85, 90]

2번 줄은 칸 값을 꺼내 그 값에 이름 score를 붙입니다. 3번 줄은 score + 5로 새 값을 만들어 이름 score만 그 값에 다시 붙일 뿐, 리스트의 칸은 건드리지 않습니다.

흔한 오답은 [75, 90, 95]입니다. 이름 score가 리스트의 칸 자체라서 다시 붙이면 칸이 바뀐다고 본 것입니다(따라 옮겨 간다는 생각). 다시 붙이기는 이름만 옮깁니다(규칙 3). 5점씩 더한 점수가 필요하면 2절처럼 새 리스트에 담습니다.

아래 코드 1번 줄 리스트 끝에 5000을 한 칸 더하면 무엇이 찍히는지 봅니다.

처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기

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

파이썬 목차로