Generator and Iterator
이터레이터는 값을 차례대로 반환하는 객체로, __iter__()
와 __next__()
메서드를 구현한다.
제너레이터는 yield
키워드를 사용하여 값을 하나씩 반환하는 함수로, 이터레이터를 생성한다.
제너레이터와 이터레이터의 주요 차이점
비교 항목 | 이터레이터 | 제너레이터 |
---|---|---|
정의 방식 | __iter__ 와 __next__ 메서드를 구현하는 클래스 | yield 키워드를 사용하는 함수 |
상태 저장 | 인스턴스 변수를 통해 명시적으로 상태 저장 | 함수의 실행 상태가 자동으로 저장 |
메모리 사용 | 모든 상태를 명시적으로 저장해야 함 | 필요한 값만 생성하여 메모리 효율적 |
구현 복잡도 | 상대적으로 복잡함 (여러 메서드 구현 필요) | 매우 단순함 (일반 함수처럼 작성) |
용도 | 복잡한 이터레이션 로직이 필요한 경우 | 간단한 순차적 데이터 생성 |
재사용성 | 클래스로 구현되어 재사용 용이 | 한 번 순회하면 소진됨 |
기능 확장성 | 클래스이므로 추가 메서드와 속성 정의 가능 | 함수 범위로 제한됨 |
성능 | 상태 관리를 위한 추가 오버헤드 존재 | 매우 가벼움 |
코드 가독성 | 구조화된 형태로 명확하나 장황할 수 있음 | 간결하고 직관적 |
양방향 통신 | 메서드를 통해 구현 가능 | send() 메서드로 기본 제공 |
이러한 차이점들은 실제 사용에서 다음과 같은 의미를 가진다.
메모리 효율성:
- 제너레이터는 모든 값을 미리 계산하지 않고 필요할 때마다 생성하므로, 대용량 데이터를 다룰 때 매우 효율적.
- 이터레이터는 상태를 직접 관리해야 하므로 더 많은 메모리를 사용할 수 있다.
구현 복잡도:
- 제너레이터는 일반 함수처럼 작성하면 되므로 구현이 매우 간단.
- 이터레이터는 클래스를 정의하고 여러 메서드를 구현해야 하므로 더 복잡.
유연성:
이터레이터는 클래스로 구현되므로 추가 메서드와 속성을 정의할 수 있어 더 복잡한 기능을 구현하기 쉽다.
제너레이터는 함수 범위로 제한되므로 기능 확장이 상대적으로 제한적.
구현 예시
|
|
각각의 사용이 적합한 상황
이터레이터가 적합한 경우:
- 복잡한 이터레이션 로직이 필요할 때
- 상태를 더 세밀하게 제어해야 할 때
- 이터레이션 객체를 재사용해야 할 때
- 추가적인 메서드나 속성이 필요할 때
제너레이터가 적합한 경우:
- 간단한 순차적 데이터 생성이 필요할 때
- 메모리 효율성이 중요할 때
- 대용량 데이터를 처리할 때
- 코드를 간단하게 유지하고 싶을 때
StopIteration
이터레이터의 동작과 관련된 중요한 예외이다.
이터레이터가 더 이상 반환할 항목이 없음을 나타낸다. 이는 이터레이션의 종료 시점을 알리는 신호 역할을 한다.
제너레이터 함수에서는 마지막 yield 문이 실행된 후 자동으로 StopIteration이 발생한다.
사용자 정의 이터레이터를 만들 때, __next__()
메서드에서 더 이상 반환할 항목이 없을 때 StopIteration을 발생시켜야 한다.
실제 활용 StopIteration은 다음과 같은 상황에서 유용하다:
- 커스텀 이터레이터 구현
- 데이터 스트림의 종료 조건 제어
- 무한 시퀀스에 종료 조건 추가
- 이터레이터 체인에서 종료 시점 제어
발생 시점
- 이터레이터의
__next__()
메서드가 더 이상 반환할 값이 없을 때 발생. - 리스트의 모든 요소를 순회한 후 다시
next()
함수를 호출하면 StopIteration이 발생한다.
주의사항
- StopIteration은 일반적인 에러가 아니므로, 예외 처리에서 별도로 고려해야 한다.
- 이터레이터가 한 번 StopIteration을 발생시키면, 해당 이터레이터는 재사용할 수 없다
- for 루프 외부에서 이터레이터를 직접 다룰 때는 StopIteration 처리를 명시적으로 해야 한다.
For 루프와의 관계
- for 루프는 내부적으로 이 예외를 사용하여 이터레이션의 종료를 감지한다.
- for 루프는 StopIteration 예외가 발생할 때까지
next()
함수를 계속 호출한다.
예시
기본적인 이터레이터와 StopIteration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class CountDown: """간단한 카운트다운 이터레이터""" def __init__(self, start): self.count = start def __iter__(self): return self def __next__(self): if self.count <= 0: # 더 이상 제공할 값이 없을 때 StopIteration 발생 raise StopIteration self.count -= 1 return self.count + 1 ## 자동 처리되는 예 countdown = CountDown(3) for num in countdown: # StopIteration이 자동으로 처리됨 print(num)
StopIteration의 내부 동작 확인
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def demonstrate_stop_iteration(): """StopIteration이 발생하는 과정을 보여주는 함수""" ## 리스트로부터 이터레이터 생성 numbers = [1, 2, 3] iterator = iter(numbers) try: print(next(iterator)) # 1 print(next(iterator)) # 2 print(next(iterator)) # 3 print(next(iterator)) # StopIteration 발생 except StopIteration: print("더 이상 원소가 없습니다!")
제너레이터에서의 StopIteration
StopIteration을 활용한 커스텀 이터레이터
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class CustomRange: """특정 범위의 숫자를 생성하는 커스텀 이터레이터""" def __init__(self, start, end, step=1): self.current = start self.end = end self.step = step def __iter__(self): return self def __next__(self): if self.step > 0 and self.current >= self.end: raise StopIteration elif self.step < 0 and self.current <= self.end: raise StopIteration value = self.current self.current += self.step return value
실제 사용 예시
|
|