파이썬

파이썬(python) - 컴프리헨션(Comprehension) 문법

티베트 모래여우 2020. 11. 25. 11:54
반응형

컴프리헨션(Comprehension) 문법이란?

컴프리헨션은 파이썬의 자료구조(list, dictionary, set)에 데이터를 좀 더 쉽고 간결하게 담기 위한 문법입니다.

여기서 말하는 '쉽고 간결하게' 데이터를 담는 방법이란 반복문과 조건문을 결합하여 하나의 구문으로 만들어 담는 것을 의미합니다.

처음 만나면 그 기괴한 생김새에 당황하실 수 있지만, 익숙해지만 정말 편하고 좋은 문법입니다.

아.. 너무 멋지다..


리스트 컴프리헨션(List Comprehension)

리스트에 순차적으로 1부터 10까지의 값을 저장하고 싶을 때 우리는 어떻게 할 수 있을까요?

가장 단순한 방법은 빈 리스트를 만들고 append 함수로 하나씩 추가하는 방법입니다.

data = []
data.append(1)
data.append(2)
...
data.append(9)
data.append(10)

하지만 이 방법은 저장해야 하는 데이터의 수가 늘어날수록 비효율적인 방법이 됩니다.

만약 1부터 10만까지의 수를 저장해야 한다면 ​append를 10만번 써야 할 테니까요.

data = []
for i in range(1, 11):
    data.append(i)

그래서 지성인답게 for문과 range 함수를 사용하는 방법을 사용 해 보았습니다.

훨씬 보기 편해졌죠?

data = list(range(1,11))

혹은 list 함수를 이용해 더 간편하게 리스트를 만들 수도 있습니다.

for문과 list 함수를 이용하는것도 좋은 방법이지만, 리스트 컴프리헨션을 이용하면 더욱 편하고 쿨하고 섹시하게 리스트를 생성할 수 있습니다.

data = [i for i in range(1, 11)]

위 코드가 1부터 10까지의 데이터를 담는 리스트를 컴프리헨션 문법으로 생성하는 코드입니다.

첫 번째 i는 리스트에 저장되는 값이고 두 번째 i는 for문의 일부입니다. 또한 전체를 대괄호로 감싸준 것을 볼 수 있습니다.

뭔가 맘에 안드시는 분들이 계실지도 모르겠습니다. 아마 어떤 분들은 "list 함수를 이용한게 훨씬 보기 좋은데요?"라고 말씀하실 수도 있겠네요.

하지만 컴프리헨션 문법의 진가는 바로 if문과 중첩 for문을 사용할 수 있다는 것입니다.

위의 리스트에서 짝수 값(2,4,6,8,10)만 저장하고 싶다고 해 봅시다.

일반 for문으로 표현하자면 다음과 같습니다.

data = []
for i in range(1, 11):
    if i % 2 == 0:
        data.append(i)

if문이 추가되니 슬슬 길어지기 시작했습니다.

하지만 리스트 컴프리헨션을 사용하면 이 또한 단 1줄로 표현할 수 있습니다.

data = [i for i in range(1, 11) if i % 2 == 0]

그저 for문 뒤에 if문을 추가해주기만 하면 됩니다. 단 변수명은 동일하게 사용해야 합니다.

훨씬 편하고 쿨하고 섹시하지 않나요?

또한 if문도 중첩해서 사용할 수 있습니다.

data = [i for i in range(1, 11) if i % 2 == 0 if i < 5]

그저 뒤에 if문을 이어서 사용하기만 하면 됩니다.

위 코드는 1부터 10까지의 숫자 중 5보다 작은 짝수를 리스트에 저장하게 됩니다.

data = [(x, y) for x in range(1, 6) for y in range(1, 4)]

# for문과 비교해봅시다.
data2 = []
for i in range(1, 6):
    for j in range(1, 4):
        data2.append((i, j))

# 출력결과
[(1, 1), (1, 2), (1, 3), 
(2, 1), (2, 2), (2, 3), 
(3, 1), (3, 2), (3, 3), 
(4, 1), (4, 2), (4, 3), 
(5, 1), (5, 2), (5, 3)]

그리고 상기했듯 컴프리헨션의 for문 또한 중첩이 가능합니다.

중첩 for문과 비교하니 훨씬 간단하죠?

마지막으로 모든 예제를 합친 리스트 컴프리헨션을 보여드리고 넘어가겠습니다.

data = [(x, y) for x in range(1, 4) for y in range(1, 4) if x % 2 == 1 if y > 1]

# 출력결과
[(1, 2), (1, 3), (3, 2), (3, 3)]

실제로 이런 코드를 쓸 일은 거의 없으니 그냥 그런갑다 하고 넘어갑시다.

그런갑다 해!

 


딕셔너리 컴프리헨션(Dictionary Comprehension)

딕셔너리 컴프리헨션 또한 기본적인 사용법은 리스트 컴프리헨션과 동일합니다.

다만 딕셔너리 자체가 키:값 으로 이루어진 자료구조인 만큼 약간 차이가 있습니다.

data = {i : i*2 for i in range(1, 6)}

# 출력결과
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10}

위 코드는 1부터 5까지를 키로 지정하고 키*2를 값으로 가지는 딕셔너리를 생성합니다.

for문 앞에 키:값을 적는다는 것과 대괄호가 중괄호로 바뀐 것만 유의하시면 됩니다.

name = ["왕춘삼", "김덕팔", "황갑득"]
age = [23, 14, 42]

data = {key: value for (key, value) in zip(name, age)}

# 출력결과
{'왕춘삼': 23, '김덕팔': 14, '황갑득': 42}

좀 더 현실적인 예제를 만들어보았습니다.

zip 함수를 활용하면 위와 같이 키와 값을 직접 가져와서 사용할 수도 있습니다.

name = ["왕춘삼", "김덕팔", "황갑득"]
age = [23, 14, 42]

data = {key: value for (key, value) in zip(name, age) if value > 20}

# 출력결과
{'왕춘삼': 23, '황갑득': 42}

물론 if문도 사용 가능합니다.

if문을 통해 20세 이상인 사람만 딕셔너리에 저장하도록 지정하였고 따라서 김덕팔씨가 제외된 모습입니다.

김덕팔씨는 우리와 함께 갈 수 없습니다!


셋 컴프리헨션(Set Comprehension)

셋 컴프리헨션은 딕셔너리 컴프리헨션과 비슷합니다.

다만 셋은 키:값의 형태가 아니기 때문에 그 부분만 유의하시면 됩니다.

data = {i for i in range(1, 11)}

# 출력결과
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

너무 간단해서 따로 드릴 말씀이 없습니다.

참고로 셋 자료구조는 중복값을 저장하지 않으니 그것 또한 유의해주세요.

base = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
data = {i for i in base}

# 출력결과
{1, 2, 3, 4, 5}

번외 : 제너레이터 컴프리헨션(Generator Comprehension)

위의 3가지 컴프리헨션 외에도 제너레이터 또한 컴프리헨션 문법으로 생성할 수 있습니다.

이는 추후 제너레이터와 yield에 대한 글을 작성할 때 같이 다루겠습니다.(같이 쓰자니 글이 너무 길어져서..)

그때까지 안-녕

반응형