[Python] yield : 제너레이터(generator) 함수

1. 기본개념

yield 를 사용하면 일반함수가 아닌 제너레이터 함수가 된다. 제너레이터 함수는 호출되더라도 즉시 실행되지 않고, 이터레이터(iterator) 를 반환한다.

2. 이터레이터(iterator)

이터레이터는 Python에서 순차적으로 데이터를 하나씩 반환할 수 있는 객체로 두 가지 조건을 충족한다.

  1. __iter__() 메서드를 가지고 있어야 한다. 이 메서드는 이터레이터 객체 자체를 반환한다.
  2. __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를 사용하면 함수가 일반 함수가 아니라 제너레이터 함수가 된다. 제너레이터 함수는 호출될 때 제너레이터 객체를 반환하며 이 객체가 이터레이터 프로토콜을 구현한 객체로서 이터레이터 객체를 반환한다.

  1. 상태 유지: yield는 함수의 실행 상태(로컬 변수, 실행 위치 등)를 저장.
  2. 지연 실행: yield는 호출될 때 값을 하나씩 반환하며, 나머지 작업은 나중으로 미룸.
  3. 무한 가능: 필요할 때 값만 계산하므로 무한 시퀀스 생성 가능.

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 예외 발생
  1. gen = simple_generator()에서 simple_generator제너레이터 객체(즉, 이터레이터)를 반환.
  2. next(gen) 호출 시 함수가 실행되고, 첫 번째 yield에서 멈추며 값을 반환.
  3. 다시 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)  # 파일 내용을 한 줄씩 처리

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Scroll to Top