리스트 컴프리헨션(list comprehensions)은 기존의 반복 가능한 객체를 기반으로 간결한 구문을 사용해 리스트를 생성하는 방법입니다:
squares = [x**2 for x in range(10)]
이 표현은 다음과 동일합니다:
squares = [] for x in range(10): squares.append(x**2)
리스트 컴프리헨션은 몇 가지 장점을 가지고 있습니다:
evens = [x for x in range(10) if x % 2 == 0];map()과의 유사:
def f(x): return x**2 squares = list(map(f, range(10)))
map은 C로 이미 존재하는 함수가 사용될 경우 대규모 데이터에서 더 빠르며, 모든 요소에 동일한 함수를 적용하는 데 적합합니다. 리스트 컴프리헨션은 기존 함수만이 아니라 모든 표현식에 적용될 수 있습니다. for 루프는 유연하지만 다소 복잡합니다.
왜
[x for x in range(10)]형태의 표현식에서 파이썬 2에서는 리스트가 실행된 후 변수 x에 접근할 수 있지만, 파이썬 3에서는 접근할 수 없나요?
답변: 파이썬 2에서는 반복 변수(x)가 리스트 컴프리헨션 실행 후 그 값을 유지합니다. 반면, 파이썬 3에서는 변수가 "격리"되어 리스트 외부에서 접근할 수 없으며, 이는 원치 않는 부작용을 방지합니다.
예시:
# Python 2.x: [x for x in range(3)] print(x) # x == 2 # Python 3.x: [x for x in range(3)] print(x) # NameError: name 'x' is not defined
이야기 1
한 개발자가 큰 프로젝트에서 리스트 컴프리헨션을 통해 필터링하고 새로운 리스트를 생성하려 했습니다:
my_list = [item.transform() for item in data if item.is_valid()]
그러나 item.is_valid()가 False를 반환할 경우 item.transform() 호출이 오류를 발생시켰습니다. 그러나 검증 함수는 잠재적인 부작용이 있는 상태로 작성되었고, 결국 리스트 컴프리헨션은 부작용이 있는 코드의 일부를 불분명하게 망치게 되었습니다.
이야기 2
프로젝트에서 파이썬 2에서 3으로 마이그레이션하는 도중, 개발자는 반복 변수가 여전히 접근 가능하다고 확신했습니다:
[x for x in range(5)] print(x) # 4를 얻을 것으로 예상했으나 NameError를 받았습니다.
이것은 반복 논리에서 변수가 컴프리헨션 외부에서 사용되어야 했던 버그를 초래했습니다.
이야기 3
명시적인 레벨 지정 없이 중첩된 리스트 컴프리헨션을 사용하는 경우:
def flatten(matrix): return [cell for row in matrix for cell in row]
초보자들은 종종 잘못된 순서로 순회하면서 오류를 발생시키며 (예: [cell for cell in row for row in matrix] 또는 이중 중첩), 이는 잘못된 결과로 이어져 — 일차원 리스트가 아닌 이차원 또는 그 반대로 나타나게 됩니다.