2.30. 컴프리헨션¶
컴프리헨션은 기존 이터러블로부터 단일 표현식으로 새 리스트, 셋, 딕셔너리, 또는 제너레이터를 만듭니다. 빈 컨테이너로 시작해 루프 안에서 추가하는 흔한 패턴을 대체합니다.
2.30.1. 리스트 컴프리헨션¶
squares = [x * x for x in range(5)]
print(squares)
출력:
[0, 1, 4, 9, 16]
같은 루프를 풀어 쓰면:
squares = []
for x in range(5):
squares.append(x * x)
컴프리헨션 형태는 리스트를 제자리에서 만드는 하나의 표현식입니다. squares = []도 없고 .append도 없습니다 – 결과가 곧 컴프리헨션의 값입니다.
앞쪽 표현식은 각 항목을 생성하고, for 절은 루프 변수를 명명하며, 선택적인 if는 항목을 걸러 냅니다.¶
2.30.2. if로 필터링하기¶
선택적인 if 절은 조건에 맞는 항목만 남깁니다:
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
출력:
[0, 2, 4, 6, 8]
필터는 앞쪽 표현식보다 먼저 실행됩니다 – x % 2 == 0이 먼저 검사되고, 조건에 맞는 값만 출력을 위해 x에 도달합니다.
2.30.3. 딕셔너리와 셋 컴프리헨션¶
같은 형태가 딕셔너리와 셋 리터럴에도 적용됩니다.
딕셔너리 컴프리헨션은 for 앞에 key: value 쌍이 있습니다:
squares = {x: x * x for x in range(5)}
print(squares)
출력:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
셋 컴프리헨션은 중괄호와 단일 표현식을 사용합니다:
unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)
출력:
{1, 2}
2.30.4. 제너레이터 표현식¶
둥근 괄호는 리스트 대신 제너레이터 표현식을 만듭니다. 값은 필요할 때 한 번에 하나씩 계산됩니다:
total = sum(x * x for x in range(1000))
백만 항목짜리 리스트는 결코 만들어지지 않습니다. 값들은 하나씩 sum()으로 흘러 들어가고, sum은 그것들을 더하면서 각 값을 그때그때 버립니다.
제너레이터 표현식은 값을 축약 함수(sum(), max(), any(), all())나 그 밖의 이터레이터를 소비하는 코드에 공급할 때 알맞은 선택입니다 – 동등한 리스트가 사용했을 메모리를 절약해 줍니다.
2.30.5. 컴프리헨션을 사용하지 말아야 할 때¶
컴프리헨션은 간결하지만 항상 더 명확한 것은 아닙니다. 다음과 같은 경우에는 평범한 for 루프를 사용하세요:
본문에 둘 이상의 문장이 필요할 때(컴프리헨션은 정확히 하나의 표현식만 담습니다).
본문에 부수 효과가 있을 때(출력, 파일 쓰기) – 컴프리헨션은 컬렉션을 만들기 위한 것이지, 동작을 실행하기 위한 것이 아닙니다.
필터나 변환에 부분이 너무 많아서 컴프리헨션이 더 이상 왼쪽에서 오른쪽으로 읽히지 않을 때.