[Python] What - 제너레이터 표현식 (Generator Expression)

하쮸·2026년 1월 14일

Error, Why, What, How

목록 보기
63/63
  • 제너레이터 관련 내용은 여기를 참고.

1. 제너레이터 표현식.

  • 리스트 컴프리헨션(Comprehension) 문법에서 대괄호, []소괄호, ()로 바꿔주면 제너레이터 표현식 (Generator Expression)이라는 문법을 만들 수 있음.
a = [
    item * item
    for item in range(0, 10)
    if item % 2 == 0
]
print(f'type(a) = {type(a)}')
print(f'a = {a}')

a = (
    item * item
    for item in range(0, 10)
    if item % 2 == 0
)
print(f'type(a) = {type(a)}')
print(f'a = {a}')
- 실행 결과-

type(a) = <class 'list'>
a = [0, 4, 16, 36, 64]

type(a) = <class 'generator'>
a = <generator object <genexpr> at 0x00000230A87DF2A0>

list_1 = [n * n for n in range(5)]
print("리스트: ", list_1)


generator_1 = (n * n for n in range(5))
print("제너레이터 객체: ", generator_1)
print("제너레이터 -> 리스트: ", list(generator_1))
- 실행 결과 -

리스트:  [0, 1, 4, 9, 16]
제너레이터 객체: <generator object <genexpr> at 0x000001DAEAE1DA40>
제너레이터 -> 리스트: [0, 1, 4, 9, 16]
  • 즉, 리스트 컴프리헨션의 경우 대괄호([])를 사용해서 리스트를 만들어서 모든 데이터를 한꺼번에 메모리에 올려 사용함.
    • 그래서 데이터가 많을수록, 즉 리스트의 크기가 커질수록 메모리 사용량이 많아짐.
[표현식 for 변수 in 데이터]		# 리스트 컴프리헨션
  • 제너레이터 표현식의 경우는 소괄호(())를 사용해서 제너레이터 객체를 만들어 놓고 필요할 때마다 데이터를 하나씩 생성함.
    • 리스트와 달리 제너레이터는 필요할 때만 값을 하나씩 꺼내서 사용하는 방식이므로 메모리를 절약할 수 있음.
(표현식 for 변수 in 데이터)		# 제너레이터 표현식

print(
    item * item
    for item in range(0, 10)
    if item % 2 == 0
)
- 실행 결과 -

<generator object <genexpr> at 0x000001D3114ADA40>
  • 위처럼 함수의 괄호로 둘러싸여 있는 경우에는 따로 소괄호(())를 사용하지 않아도 제너레이터 표현식으로 인식됨.

2. 리스트 컴프리헨션 -> 제너레이터 표현식으로 대체.

  • 제너레이터 표현식 (Generator Expression)은 대부분의 경우 리스트 컴프리헨션(Comprehension)를 대체할 수 있기 때문에 가능하다면 대체하는 것이 좋음.

2-1. 가능하다면 대체하는 것이 좋음.

  • why?
    • 리스트 컴프리헨션을 이용하여 크기가 큰 리스트를 만들 경우 메모리 사용량이 많아지지만
      제너레이터 표현식은 제너레이터 객체만을 만들 뿐임. 그래서 메모리 사용량이 적음.

2-2. 메모리 비교.

import sys

# 1억개로 비교.

list_comp = [i for i in range(100000000)]
gen_exp = (i for i in range(100000000))

# Byte -> MB 변환
list_mb = sys.getsizeof(list_comp) / (1024 * 1024)
gen_mb = sys.getsizeof(gen_exp) / (1024 * 1024)

print(f'리스트 메모리 크기: {list_mb:.5f} MB')
print(f'제너레이터 메모리 크기: {gen_mb:.5f} MB')
- 실행 결과 -

리스트 메모리 크기: 796.44070 MB
제너레이터 메모리 크기: 0.00019 MB

2-3. 대체하면 안 되는 케이스.


2-3-1. 미리 처리해 두고 요청이 있을 때 즉시 데이터를 응답해야하는 경우.

origin = [1, 2, 3, 4, 5]
list_comp = [str(i) for i in origin]
print("리스트 컴프리헨션:", ', '.join(list_comp))

-------------------------------------------------------

origin = [1, 2, 3, 4, 5]
gen_exp = (str(i) for i in origin)
print("제너레이터 익스프레션:", ', '.join(gen_exp))
  • 리스트 컴프리헨션의 경우 list_comp = [str(i) for i in origin] 이때 처리가 일어남.
    제너레이터 표현식의 경우 print("제너레이터 익스프레션:", ', '.join(gen_exp)) 이때 처리가 일어남.
    • 따라서 미리 처리해 두고 요청이 있을때 곧바로 데이터를 응답해야 하는 상황이라면 리스트 컴프리헨션을 사용하는 것이 적절함.

2-3-2. 원본의 변경이 반영되면 안 되는 상황.

origin = [1, 2, 3, 4, 5]
list_comp = [str(i) for i in origin]
gen_exp = (str(i) for i in origin)

# 원본의 첫 번째 요소를 변경
origin[0] = 9999

print('리스트 컴프리헨션: ', ', '.join(list_comp))
print('제너레이터 익스프레션: ', ', '.join(gen_exp))
- 실행 결과 -

리스트 컴프리헨션:  1, 2, 3, 4, 5
제너레이터 익스프레션:  9999, 2, 3, 4, 5
  • 리스트 컴프리헨션의 경우 원본을 변경하는 시점 전에 처리가 돼서 원본을 변경하더라도 반영되지 않음.
  • but 제너레이터 표현식의 경우 원본을 변경하는 시점 이후에 처리가 돼서 원본을 변경하면 반영이 됨.

3. 참고.

  • 파이써닉 파이썬 (Pythonic Python)
  • 혼자 공부하는 파이썬.
profile
Every cloud has a silver lining.

0개의 댓글