본문 바로가기
Dev/Python

[Python] 파이썬 이터레이터와 제너레이터: 메모리를 잡아먹는 괴물 리스트 대신 현명하게 데이터 다루기

by Yoon_estar 2025. 9. 27.
728x90
반응형

개요

대용량 데이터를 다룰 때 필수적인 이터레이터와 제너레이터에 대해 쉽고 명확하게 정리해 보려고 합니다. 이 두 가지를 제대로 이해하면 코드를 더 효율적이고 간결하게 작성할 수 있습니다. 

 

이터레이터(Iterator)란?

개념 : 데이터를 순서대로 하나씩 꺼내는 장치

 

이터레이터(Iterator)는 반복하는 장치라는 의미 그대로, 데이터를 순서대로 하나씩 꺼낼 수 있는 객체입니다. 리스트나 튜플처럼 모든 데이터를 메모리에 한꺼번에 올려놓는 방식이 아니라 필요할 때마다 값을 하나씩 가져오는 똑똑한 객체라고 볼 수 있습니다.

 

핵심 용어 정리

  • 이터러블(Iterable) : for 루프에 사용할 수 있는 객체. __iter__() 메서드를 가지고 있습니다. 리스트, 튜플, 문자열 등이 대표적인 이터러블입니다. 
  • 던더(Dunder) 메서드: __로 시작하고 끝나는 특별한 메서드(ex. __iter__, __next__) 사용자가 직접 호출하기보다는 파이썬 내부 동작에 의해 자동으로 호출됩니다.
  • StopIteration 예외 : 이터레이터가 더 이상 반환할 값이 없을 때 발생하는 예외입니다. next() 함수를 호출했을 때 이 예외가 발생하면 반복이 끝났다는 신호입니다.

왜 필요할까

이터레이터의 가장 큰 장점은 메모리 효율성입니다. 

  • 메모리 절약 : 1억 개의 데이터를 리스트로 만들면 메모리가 부족할 수 있지만, 이터레이터는 값을 하나씩 생성 하므로 메모리를 훨씬 적게 사용합니다. 
  • 일관된 인터페이스 : for 루프, while 루프, next() 함수 등 다양한 파이썬 반복 구문이 이터레이터 프로토콜을 기반으로 작동하기 때문에, 모든 자료형을 통일된 방식으로 다룰 수 있습니다. 
  • 무한 데이터 처리 : 끝이 없는 데이터 스트림(예: 실시간 로그, 무한 수열)도 문제 없이 처리할 수 있습니다. 

이터레이터 사용하기 

1. 내장 이터레이터 사용하기

파이썬의 기본 자료형들은 이미 이터레이터 프로토콜을 따릅니다. iter() 함수로 이터레이터 객체를 만들고, next() 함수로 값을 하나씩 꺼낼 수 있습니다.

numbers = [10, 20, 30]
it = iter(numbers)

print(next(it))  # 출력: 10
print(next(it))  # 출력: 20
print(next(it))  # 출력: 30
# next(it)를 다시 호출하면 StopIteration 예외 발생

 

2. 사용자 정의 이터레이터 만들기

__iter__()와 __next__() 메서드를 구현하여 나만의 이터레이터를 만들 수 있습니다.

class CountDown:
    def __init__(self, start):
        self.current = start
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        self.current -= 1
        return self.current + 1

countdown = CountDown(3)
iterator = iter(countdown)

print(next(iterator))  # 출력: 3
print(next(iterator))  # 출력: 2
print(next(iterator))  # 출력: 1

 

제너레이터(Generator)는 이터레이터와 무엇이 다를까?

개념 : 이터레이터를 자동으로 만들어주는 문법

 

제너레이터(Generator)는 이터레이터를 더욱 쉽고 간결하게 만들 수 있는 특별한 함수나 표현식입니다. 이터레이터 클래스를 직접 만들 필요 없이 yield 키워드만 사용하면 자동으로 이터레이터처럼 동작하는 객체를 생성해 줍니다.

 

핵심 특징

  • yield 키워드 : return과 비슷하지만, 값을 반환한 후 함수의 실행 상태를 그대로 일시정지 시킵니다. next()가 다시 호출되면 멈췄던 시점부터 실행을 재개합니다. 
  • 지연 평가(Lazy Evaluation) : 모든 결과를 미리 계산하지 않고 값이 필요할 때만 계산을 수행합니다. 덕분에 메모리를 절약하고 불필요한 연산을 피할 수 있습니다.

왜 필요할까?

제너레이터는 이터레이터의 장점을 그대로 가져오면서, 코드의 간결성을 극대화합니다.

  • 메모리 효율성 : 이터레이터와 동일하게 대용량 데이터를 처리할 때 메모리를 절약합니다.
  • 간결한 문법 : __iter__와 __next__ 메서드를 직접 구현할 필요가 없어 코드가 훨씬 짧고 가독성이 좋습니다.

제너레이터 사용하기

1. 제너레이터 함수

함수 내부에 yield 키워드를 사용하여 제너레이터를 만듭니다.

def countdown_generator(n):
    while n > 0:
        yield n
        n -= 1

gen = countdown_generator(3)

print(next(gen))  # 출력: 3
print(next(gen))  # 출력: 2
print(next(gen))  # 출력: 1

 

2. 제너레이터 표현식

리스트 컴프리헨션과 비슷하지만, 대괄호[]  대신 소괄호()를 사용합니다.

squares = (x * x for x in range(5))
print(next(squares))  # 출력: 0
print(next(squares))  # 출력: 1

 

이터레이터 VS 제너레이터 : 무엇을 사용해야 할까?

구분 이터레이터(클래스) 제너레이터(함수, 표현식)
생성 방법 __iter__() 와 __next() 메서드를 가진 클래스 yield를 사용하는 함수 또는 () 표현식
메모리 효율성 O(동일) O(동일)
코드 간결성 상대적으로 복잡 매우 간결하고 직관적
주요 사용처 복잡한 상태를 관리하거나 재사용 가능한 반복 로직이 필요할 때 대부분의 경우 특히 간단한 반복 로직이나 대용량 데이터 처리 시

 

대부분의 경우 제너레이터를 사용하는 것이 훨씬  효율적입니다. 코드가 간결하고 작성하기 쉽기 때문입니다. 하지만, 반복을 위해 여러 상태를 복잡하게 관리해야 하거나 객체를 재사용해야 하는 경우라면 이터레이터 클래스를 직접 정의하는 것이 더 적합할 수 있습니다.

 

결론

이터레이터와 제너레이터는 파이썬의 핵심 철학인 메모리 효율성과 코드 간결성을 잘 보여주는 개념입니다.무턱대고 리스트에 모든 데이터를 담는 대신, 이 둘을 활용하면 메모리 문제를 해결하고 코드를 더 우아하게 만들 수 있습니다. 오늘 배운 내용을 잘 기억해두셨다가 필요한 순간에 멋지게 활용하시길 바랍니다.

반응형

'Dev > Python' 카테고리의 다른 글

[Python] Python 예외 처리  (0) 2025.09.26
[Python] 인자 규약  (0) 2025.09.25
[Python] 함수 시그니처  (0) 2025.09.24
[Python] 모듈(Module) & 패키지(Package)  (0) 2025.09.23
[Python] 타입 힌트  (0) 2025.09.22