프로그래밍백엔드 개발자

파이썬에서 생성기 표현식이란 무엇이며, 생성기 함수 및 리스트 표현식과 어떻게 다른지, 그리고 그 사용이 가장 적절한 경우는 어떤 것인지에 대해 설명해 주세요.

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

답변

질문 배경

파이썬은 2.4 버전부터 리스트 표현식(list comprehensions)에 "생성기 표현식"(generator expressions)을 추가했습니다. 이는 값의 지연 시퀀스를 생성할 수 있게 해주며, 생성기와 비슷하지만 간결하고 가독성이 좋은 형태입니다.

문제

리스트 표현식([x for x in iterable])은 모든 요소를 메모리에 즉시 로드하여 리스트를 생성합니다. 이는 요소의 수가 매우 많을 경우 비효율적이거나 심지어 위험할 수 있습니다. 생성기 함수(yield를 사용하는)는 더 유연하지만, 별도의 함수 정의와 더 많은 코드 줄을 요구합니다.

해결책

생성기 표현식((x for x in iterable))은 여유 있는 문법을 제공하여 지연된 시퀀스를 생성합니다(요소는 필요 시 계산되며, 모두 한 번에 로드되지 않습니다). 이는 리스트 표현식과 비슷하게 보이지만, 소괄호를 사용합니다:

# 리스트 표현식은 모든 것을 메모리에 로드함 squares_list = [x**2 for x in range(10**6)] # 생성기 표현식: 요소는 요청 시 제공되며, 메모리를 거의 사용하지 않음 squares_gen = (x**2 for x in range(10**6)) # 생성기의 처음 5개 값을 가져옴 for _ in range(5): print(next(squares_gen))

주요 특징:

  • 생성기 표현식은 전체 컬렉션을 메모리에 즉시 로드하지 않음
  • 임의의 반복 가능한 객체가 필요한 장소에서 사용됨(예: sum(), max(), any() 등)
  • 문법이 간결하며 별도의 함수 정의가 필요하지 않음

예상 질문.

같은 생성기 표현식을 여러 번 반복할 수 있나요?

아니요, 한 번 반복한 후 생성기는 "소진"됩니다. 다시 반복하려면 새로운 생성기를 만들거나 리스트 표현식을 사용해야 합니다.

it = (x for x in range(3)) print(list(it)) # [0,1,2] print(list(it)) # [] — 더 이상 값을 얻을 수 없음

생성기는 사용 간 상태를 유지하나요?

네, 생성기 표현식은 next() 호출 간에 "위치"를 유지하지만, 새 객체를 만들지 않는 한 처음으로 재설정할 수는 없습니다.

한 줄에서 생성기 표현식을 여러 번 사용할 수 있나요?

아니요! 생성기를 한 번에 여러 곳에 "언팩"하면(예: 여러 함수에 동시에 전달하고 리스트로 반환하지 않으면), 일부 데이터가 손실됩니다 — 각 자식 사용은 포인터를 앞으로 이동시킵니다.

g = (x for x in range(3)) print(sum(g), list(g)) # sum(g)는 모두 얻지만, list(g)는 비게 됨

일반적인 오류 및 안티 패턴

  • 컬렉션이 전체가 필요한 경우 생성기 표현식을 사용하면 단 한 번 사용 가능하게 되며, 이후 데이터가 손실됨
  • "소진된" 생성기를 대신하여 전달 시 빈 컬렉션을 얻게 됨

실제 사례

부정적 케이스

대용량 파일을 분석하는 프로젝트에서 사용됨:

data = (parse_line(line) for line in file) process(list(data)) other_process(list(data))

장점:

  • 모든 데이터에 대해 코드를 쉽게 수정 가능

단점:

  • 첫 번째 호출 후 list(data)에서 생성기가 끝나면서 데이터가 첫 번째 처리기만 전달되고, 두 번째는 아무것도 받지 못함

긍정적 케이스

데이터의 재사용이 필요할 때 리스트 컴프리헨션을 사용하거나, 일회용 소비를 위해 생성기를 생성함:

# 분석을 위한 일회용 생성기(예: 합계 계산) total = sum(parse_line(line) for line in file)

장점:

  • 메모리 절약, 코드의 간단함

단점:

  • 생성기를 재생성하지 않으면 데이터를 재사용할 수 없음