본문으로 건너뛰기

리스트 컴프리헨션

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

목차

리스트 컴프리헨션(list comprehension)은 for와 if를 대괄호 안에 써서 새 리스트를 만드는 꼴입니다. 빈 리스트를 두고 반복하며 append()로 담던 거르기와 바꿔 담기를 한 문장으로 씁니다.

파이썬 코드에서 자주 만나는 꼴이라, 처음 보면 낯설어도 같은 일을 하는 for 꼴로 바꿔 읽을 수 있으면 됩니다. 이 레슨은 두 꼴을 나란히 놓고 같은 부분을 짝지어 읽습니다.

13단계 중 1단계. 같은 일을 두 꼴로 씁니다. 3~5번 줄을 따라가며 6~7번 줄의 같은 부분을 짚습니다.

1for 꼴과 컴프리헨션 꼴

그림의 코드는 4,000원 넘는 가격만 골라 담는 같은 일을 두 꼴로 씁니다. 2~5번 줄은 거르기와 바꿔 담기에서 쓴 for 꼴이고, 6~7번 줄이 컴프리헨션 꼴입니다.

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

6~7번 줄은 한 문장이고, 폰 화면에 맞게 if 앞에서 줄을 나눴습니다. 두 꼴의 같은 부분을 짝지으면 이렇습니다.

하는 일for 꼴컴프리헨션 꼴
빈 리스트picked = []대괄호 [ ]
하나씩 꺼내기for price in prices:for price in prices
맞으면if price > 4000:if price > 4000
담기picked.append(price)맨 앞 price

컴프리헨션 꼴을 말로 적으면 이렇습니다.

[식 for 이름 in 리스트 if 조건]

가운데 for부터 읽습니다. 리스트에서 값을 하나씩 꺼내 이름을 붙이고, if 조건이 참이면 맨 앞 식의 값을 새 리스트에 담습니다. 값마다 이 일을 되풀이하는 것은 for 꼴의 덩어리와 같습니다(규칙 4). 다 돌고 나면 그 새 리스트가 식의 값이 되고, 6번 줄은 그 값에 이름 big을 붙입니다(규칙 2).

2맨 앞 식이 담을 값을 정한다

if를 빼면 꺼낸 값을 모두 담습니다. 맨 앞 자리에는 이름만이 아니라 식을 써서 값을 바꿔 담을 수 있습니다. 아래 코드는 무엇을 찍을까요?

prices = [4000, 4500, 3500]
up = [price + 500
      for price in prices]
print(up)
print(prices)
실행 결과 보기
실행 결과
[4500, 5000, 4000]
[4000, 4500, 3500]

예상과 다르면 그곳이 배울 곳입니다. 맨 앞 식 price + 500을 꺼낸 값마다 계산해 그 결과를 새 리스트에 담습니다. 거르기와 바꿔 담기 레슨에서 모든 가격을 500원 올린 바꿔 담기와 같은 결과입니다. 컴프리헨션은 언제나 새 리스트를 만듭니다. prices가 가리키는 리스트는 건드리지 않아서 5번 줄은 처음 값 그대로 찍습니다.

예제

컴프리헨션 안의 이름을 밖에서 쓰면

nums = [1, 2, 3]
twice = [x * 2 for x in nums]
print(x)
실행 결과
Traceback (most recent call last):  File "main.py", line 3, in <module>    print(x)          ^NameError: name 'x' is not defined

맨 아래 줄은 x라는 이름이 없다는 뜻입니다. 컴프리헨션 안에서 붙인 이름 x는 그 대괄호 안에서만 쓰이고, 다 돌고 나면 남지 않습니다. for와 range에서 본 for 꼴은 반복이 끝나도 이름이 마지막 값에 붙어 남는 것과 다릅니다. 마지막 값이 필요하면 nums[-1]처럼 리스트에서 꺼냅니다.

자주 틀리는 곳

틀린 생각: 맨 앞에 조건을 쓰면 조건에 맞는 값만 담긴다.

for 꼴에서는 if 줄이 append()보다 먼저 나오니, 컴프리헨션에서도 앞에 조건을 두면 거를 것 같습니다. 맨 앞 자리는 거르는 자리가 아니라 담을 값을 정하는 자리입니다.

prices = [4000, 4500, 3500]
big = [price > 4000
       for price in prices]
print(big)
실행 결과
[False, True, False]

맨 앞 식 price > 4000을 값마다 계산한 결과 False, True, False가 그대로 담겼습니다. 거르지 않아서 값의 수도 셋 그대로입니다.

맞는 규칙: 맨 앞 식은 값마다 계산해 담을 값을 정하고, 거르는 일은 for 뒤의 if가 합니다. 4,000원 넘는 가격을 담으려면 맨 앞에 price를, 뒤의 if에 조건을 씁니다.

틀린 생각: 컴프리헨션은 꺼내 온 리스트의 값을 바꾼다.

price + 500이 prices의 값마다 계산되니 prices 안의 값이 바뀌는 것처럼 보입니다. 컴프리헨션은 새 리스트를 만들 뿐입니다.

prices = [4000, 4500]
up = [price + 500
      for price in prices]
print(prices)
실행 결과
[4000, 4500]

2~3번 줄이 만든 새 리스트에는 up이 붙고, prices가 가리키는 리스트는 처음 그대로입니다.

맞는 규칙: 컴프리헨션은 언제나 새 리스트를 만들어 돌려주고, 꺼내 온 리스트는 바꾸지 않습니다. 바꾼 값은 새 리스트에 붙인 이름으로 꺼냅니다(규칙 2).

확인 문제

1. 1절 코드의 컴프리헨션 조건을 바꿨습니다. 무엇이 찍힐까요?

prices = [4000, 4500, 3500]
low = [price for price in prices
       if price < 4500]
print(low)
힌트

꺼내는 차례대로 값마다 price < 4500이 참인지 적어 봅니다.

정답
실행 결과
[4000, 3500]

4000과 3500은 4500보다 작아 담기고, 4500은 4500 < 4500이 False라 담기지 않습니다. 담는 차례는 꺼낸 차례 그대로입니다.

흔한 오답은 [4000, 4500, 3500]입니다. 4500도 조건을 지난다고 본 것입니다. < 연산자는 두 값이 같으면 False입니다.

2. 4,000원보다 싼 가격만 500원 올려 담는 for 꼴입니다.

prices = [3000, 4500, 3500]
up = []
for price in prices:
    if price < 4000:
        up.append(price + 500)
print(up)
실행 결과
[3500, 4000]

같은 일을 하는 컴프리헨션 꼴의 빈칸 둘을 채우세요. 다 채운 코드도 [3500, 4000]을 찍어야 합니다.

prices = [3000, 4500, 3500]
up = [________
      for price in prices
      if ________]
print(up)
힌트

for 꼴의 5번 줄에서 담는 값과 4번 줄의 조건을 찾아 봅니다.

정답

차례로 price + 500과 price < 4000입니다.

prices = [3000, 4500, 3500]
up = [price + 500
      for price in prices
      if price < 4000]
print(up)
실행 결과
[3500, 4000]

for 꼴에서 append()에 넘긴 값이 맨 앞 식이 되고, if 줄의 조건이 뒤의 if 자리로 갑니다.

다르게 써도 되는 곳: 500 + price, 4000 > price도 같습니다.

흔한 오답은 앞 빈칸에 price만 쓰는 것입니다. 거르기는 맞지만 올리지 않은 값이 담겨 [3000, 3500]이 찍힙니다. 맨 앞 자리에는 꺼낸 이름을 쓴다고 본 것입니다. 담을 값은 맨 앞 식이 정합니다.

3. 60점이 안 되는 점수에만 5점을 더해 새 리스트에 담습니다. 무엇이 찍힐까요?

scores = [55, 90, 58]
bonus = [score + 5
         for score in scores
         if score < 60]
print(bonus)
힌트

꺼낸 score마다 4번 줄의 조건부터 따져 봅니다.

정답
실행 결과
[60, 63]

55와 58만 score < 60이 참이라 담기고, 담는 값은 맨 앞 식 score + 5라 60과 63입니다. 90은 조건이 거짓이라 담기지 않습니다.

흔한 오답은 [60, 90, 63]입니다. if가 바꿀 값만 고르고 나머지는 그대로 담는다고 본 것입니다. 조건이 거짓인 값은 새 리스트에 들지 않습니다.

아래 코드 7번 줄에서 if price > 4000만 지우면(닫는 ]는 남깁니다) 8번 줄이 무엇을 찍는지 봅니다.

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

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

파이썬 목차로