프로그래밍백엔드 개발자

파이썬에서 리스트 컴프리헨션(list comprehensions)의 작동 메커니즘을 설명하세요. 리스트 컴프리헨션은 map() 함수 및 for 루프와 어떻게 다르며, 각 접근 방식의 장단점과 부주의한 사용 시 발생할 수 있는 오류는 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

리스트 컴프리헨션(list comprehensions)은 기존의 반복 가능한 객체를 기반으로 간결한 구문을 사용해 리스트를 생성하는 방법입니다:

squares = [x**2 for x in range(10)]

이 표현은 다음과 동일합니다:

squares = [] for x in range(10): squares.append(x**2)

리스트 컴프리헨션은 몇 가지 장점을 가지고 있습니다:

  • 간결함과 가독성 (특히 간단한 변환의 경우);
  • 조건을 포함할 수 있는 가능성 (filter): 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] 또는 이중 중첩), 이는 잘못된 결과로 이어져 — 일차원 리스트가 아닌 이차원 또는 그 반대로 나타나게 됩니다.