생성기는 전체 컬렉션을 한 번에 메모리에 할당하지 않고 "즉시" 시퀀스를 생성할 수 있는 파이썬의 특별한 반복 가능 객체입니다. yield 키워드를 사용한 함수나 생성기 표현식((expr for ... in ...))을 통해 구현됩니다. 이는 대량의 데이터나 잠재적으로 무한한 스트림을 처리할 때 유용합니다.
리스트 표현식과의 주요 차이점:
[x for x in range(10)])은 메모리에 즉시 전체 리스트를 생성합니다.(x for x in range(10)))는 요소를 하나씩 생성하여 메모리 사용량이 훨씬 적습니다.생성기를 사용할 때:
# 생성기 함수 def counter(n): for i in range(n): yield i for number in counter(5): print(number)
"yield가 있는 함수와 일반적인 리스트를 반환하는 함수의 차이점은 무엇인가요? 예를 들어 설명하세요."
답변:
일반 함수는 즉시 리스트를 계산하고 반환하여 모든 요소에 대한 메모리를 차지합니다. yield가 있는 함수는 생성기를 반환하여 요소를 하나씩 제공하며 전체 시퀀스를 한 번에 메모리에 로드하지 않습니다.
def make_list(n): return [i for i in range(n)] # 즉시 리스트를 반환, 메모리가 많이 소요됨 def make_generator(n): for i in range(n): yield i # 하나의 요소씩 반환
이야기
대량의 로그를 처리하기 위한 프로젝트에서 오류가 포함된 문자열을 추출하기 위해 리스트 표현식을 사용했습니다:
error_lines = [line for line in open('biglog.txt') if 'ERROR' in line]
파일 크기가 2GB를 초과하여 애플리케이션이 OOM(Out of Memory) 오류가 발생했습니다. 생성기를 사용해야 했습니다:
error_lines = (line for line in open('biglog.txt') if 'ERROR' in line)
이야기
직원이 짧은 리스트를 분석하고 싶어 yield가 있는 함수를 작성했지만 반환되는 것이 리스트가 아닌 생성기라는 것을 잊었습니다:
result = my_generator_function() # result는 리스트가 아닌 생성기입니다. if len(result) > 5: # TypeError: type 'generator' 객체에는 길이(len)가 없습니다.
수정: 결과를 list()로 감싸야 합니다.
이야기
생성자를 여러 번 순환(iterate)하려고 했습니다:
numbers = (i for i in range(5)) for n in numbers: pass # 생성기가 소진되었습니다. for n in numbers: print(n) # 아무것도 출력하지 않습니다.
생성기는 일회성입니다. 반복 사용을 위해서는 새 생성기를 생성해야 합니다.