1. 기본개념
yield 를 사용하면 일반함수가 아닌 제너레이터 함수가 된다. 제너레이터 함수는 호출되더라도 즉시 실행되지 않고, 이터레이터(iterator) 를 반환한다.
2. 이터레이터(iterator)
이터레이터는 Python에서 순차적으로 데이터를 하나씩 반환할 수 있는 객체로 두 가지 조건을 충족한다.
__iter__()
메서드를 가지고 있어야 한다. 이 메서드는 이터레이터 객체 자체를 반환한다.__next__()
메서드를 가지고 있어야 한다. 이 메서드는 이터레이터가 가진 데이터 중 다음 값을 반환한다.
2-1. 이터러블(iterable)과 이터레이터의 차이
- 이터러블(iterable): 순회 가능한 객체(예: 리스트, 튜플, 문자열 등).
__iter__()
메서드를 호출하면 이터레이터를 반환.- 이터러블은 이터레이터를 생성할 수 있는 객체이다.
- 이터레이터(iterator): 이터러블로부터 생성된 객체
__next__()
를 호출해 값을 하나씩 반환하며 상태를 기억한다
Python
# iterable 과 iterator 내부함수 확인
print(f'dir(list): {dir(list)}')
iterator = iter([1,2,3])
print()
print(f'dir(iterator): {dir(iterator)}')
이터러블한 list의 내부에서는 __iter__만 존재하는 것을 볼 수 있고, 내부 함수의 __Iter__() 메서드를 호출한 결과인 iterator의 내부함수에서는 __next__()를 관찰 할 수 있다.
Python
# 리스트는 이터러블
numbers = [1, 2, 3]
# 이터레이터 생성
iterator = iter(numbers)
# 이터레이터에서 값을 순차적으로 가져오기
print(next(iterator)) # 출력: 1
print(next(iterator)) # 출력: 2
print(next(iterator)) # 출력: 3
# print(next(iterator)) # StopIteration 예외 발생 (더 이상 값이 없음)
3. yield
yield
를 사용하면 함수가 일반 함수가 아니라 제너레이터 함수가 된다. 제너레이터 함수는 호출될 때 제너레이터 객체를 반환하며 이 객체가 이터레이터 프로토콜을 구현한 객체로서 이터레이터 객체를 반환한다.
- 상태 유지:
yield
는 함수의 실행 상태(로컬 변수, 실행 위치 등)를 저장. - 지연 실행:
yield
는 호출될 때 값을 하나씩 반환하며, 나머지 작업은 나중으로 미룸. - 무한 가능: 필요할 때 값만 계산하므로 무한 시퀀스 생성 가능.
3-1. 제너레이터 함수의 동작
제너레이터 함수가 호출되면, 즉시 실행되지 않고 이터레이터 객체를 반환. 이후, 이터레이터의 __next__()
메서드를 호출할 때마다 함수가 실행되어 yield
로 값을 반환.
Python
def simple_generator():
print("첫 번째 값 생성")
yield 1
print("두 번째 값 생성")
yield 2
print("세 번째 값 생성")
yield 3
# 제너레이터 함수 호출
gen = simple_generator()
# 이터레이터의 __next__ 호출
print(next(gen)) # "첫 번째 값 생성" 출력 후 1 반환
print(next(gen)) # "두 번째 값 생성" 출력 후 2 반환
print(next(gen)) # "세 번째 값 생성" 출력 후 3 반환
print(dir(gen)) # '__iter__', '__next__' 존재
# print(next(gen)) # StopIteration 예외 발생
gen = simple_generator()
에서simple_generator
는 제너레이터 객체(즉, 이터레이터)를 반환.next(gen)
호출 시 함수가 실행되고, 첫 번째yield
에서 멈추며 값을 반환.- 다시
next(gen)
를 호출하면 저장된 상태에서 실행을 재개.
4. 제너레이터 함수와 일반 함수의 차이
특징 | 일반 함수 | 제너레이터 함수 |
---|---|---|
반환값 | 한 번에 하나의 값 반환 (return ) | yield 로 값을 하나씩 반환 |
호출 결과 | 함수의 실행 결과를 반환 | 제너레이터 객체를 반환 |
실행 방식 | 호출 시 즉시 실행 | next() 가 호출될 때 실행 시작 |
상태 유지 | 호출 시 매번 새로 실행 | 이전 상태를 기억하고 중단 위치부터 실행 |
5. 제너레이터 함수의 장점
제너레이터는 필요한 순간에 데이터를 생성하기 떄문에, 대용량 데이터 처리에 적합하다.
Python
def big_range(n):
for i in range(n):
yield i
for num in big_range(10**6): # 큰 데이터를 메모리 낭비 없이 처리
if num > 10: # 10까지만 출력
break
print(num)
제너레이터는 큰 데이터 구조나 동적 데이터를 간단하게 처리
Python
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
for line in read_large_file('large_file.txt'):
print(line) # 파일 내용을 한 줄씩 처리