**제너레이터 표현식(Generator Expression)**은 리스트 컴프리헨션과 비슷하게 생겼지만, 동작 방식은 완전히 다른 아주 똑똑한 도구입니다.
쉽게 비유하자면, 리스트 컴프리헨션은 **“사탕 100개가 든 봉지를 한꺼번에 사는 것”**이고, 제너레이터 표현식은 **“필요할 때마다 사탕을 하나씩 나오는 기계”**를 갖는 것과 같습니다.
1. 문법적 차이
가장 큰 차이는 괄호의 모양입니다.
-
리스트 컴프리헨션:
[대괄호]사용 → 결과값이 바로 리스트로 생성됨. -
제너레이터 표현식:
(소괄호)사용 → 제너레이터 객체가 생성됨.
Python
# 리스트 컴프리헨션
list_comp = [x * x for x in range(10)]
# 결과: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] (메모리에 다 올라감)
# 제너레이터 표현식
gen_exp = (x * x for x in range(10))
# 결과: <generator object ...> (계산할 준비만 끝낸 상태)
2. 왜 제너레이터를 쓸까요? (핵심 장점)
① 메모리 효율성 (Lazy Evaluation)
만약 1억 개의 숫자를 다뤄야 한다면, 리스트는 1억 개의 데이터를 모두 메모리에 올려야 해서 컴퓨터가 멈출 수 있습니다. 하지만 제너레이터는 **“다음 데이터는 뭐야?”**라고 요청받을 때만 그 데이터를 계산해서 보여줍니다.
② 처리 속도 (Short-circuit)
예를 들어, “이 리스트에 짝수가 하나라도 있어?”라는 질문에 답할 때, 리스트는 전체를 다 검사해서 리스트를 만든 뒤 확인하지만, 제너레이터는 첫 번째 짝수를 찾는 순간 계산을 멈출 수 있습니다.
3. 언제, 어떻게 사용하나요?
주로 max(), min(), sum(), any(), all() 같은 집계 함수에 데이터를 던져줄 때 가장 많이 사용합니다.
Python
# 1. 합계 구하기
total = sum(x for x in range(1000000)) # 메모리 낭비 없이 합계만 계산
# 2. 조건에 맞는 데이터 확인
# 파일 리스트 중 .py 파일이 하나라도 있는지 확인
has_python_file = any(name.endswith('.py') for name in file_list)
주의할 점: 제너레이터는 ‘일회용’입니다. 한 번 끝까지 데이터를 꺼내 쓰면 다시 사용할 수 없으므로, 여러 번 반복해서 데이터를 써야 한다면 리스트로 만드는 것이 낫습니다.
4. 질문하신 코드 다시 보기
Python
max_len = max(len(row) for row in lst)
여기서 (len(row) for row in lst)는 소괄호가 생략된 제너레이터 표현식입니다. (함수의 유일한 인자로 들어갈 때는 소괄호 생략 가능)
-
max함수가 “야, 첫 번째 값 줘봐”라고 하면, -
제너레이터가
lst[0]의 길이를 계산해서max에게 줍니다. -
max가 “다음 값은?” 하면 그제야lst[1]의 길이를 계산합니다. -
이 과정을 반복하며 최댓값 하나만 딱 남기고 나머지는 메모리에서 잊어버립니다.
이 개념이 이해되셨나요? 아니면 제너레이터와 리스트 중 어떤 상황에 어떤 걸 쓰는 게 좋을지 실제 예시가 더 궁금하신가요?