파이썬에서 Generator를 사용하는 이유와 사용법

파이썬에서 Generator를 사용하는 이유와 사용법

Python
파이썬에서 Generator를 사용하는 이유와 사용법
Author

gabriel yang

Published

October 2, 2024


Generator는 파이썬에서 큰 데이터를 효율적으로 처리하거나, 메모리를 절약하면서도 동적으로 값을 생성하고자 할 때 유용하게 사용되는 기능입니다. 일반적인 함수와는 다르게, Generator는 한 번에 하나의 값을 생성하고, 필요할 때마다 그 값을 계산하는 특징을 가집니다.

1. Generator를 사용하는 이유

1.1. 메모리 효율성

리스트와 같은 자료구조는 모든 값을 한 번에 메모리에 저장하기 때문에, 큰 데이터를 다룰 때 많은 메모리가 필요합니다. 하지만 Generator는 필요할 때마다 값을 생성하기 때문에 메모리를 절약할 수 있습니다. 특히 매우 큰 데이터셋을 처리할 때 Generator를 사용하면 성능을 크게 향상시킬 수 있습니다.

1.2. 값의 지연 평가(Lazy Evaluation)

Generator는 지연 평가를 지원합니다. 즉, 값을 필요로 할 때마다 그때 생성하여 반환하는 방식입니다. 이를 통해 값을 미리 계산하지 않고도, 효율적인 처리가 가능합니다. 예를 들어, 수십만 개의 데이터를 다룬다고 했을 때, 리스트는 모든 데이터를 한 번에 메모리에 담지만, Generator는 필요할 때마다 값을 하나씩 반환합니다.

1.3. 무한 데이터 스트림 처리

무한한 데이터 스트림을 처리할 때도 Generator는 적합합니다. 예를 들어, 끝이 없는 시퀀스를 생성하거나 실시간으로 데이터를 제공하는 경우에도 사용할 수 있습니다.

2. Generator 생성 방법

2.1. yield 키워드를 사용하는 함수 기반 Generator

파이썬에서 Generator는 yield 키워드를 사용하여 생성할 수 있습니다. yield는 함수 내에서 값을 반환하면서 함수의 상태를 기억합니다. 그리고 함수가 다시 호출되면 이전 상태에서 이어서 실행됩니다.

예제 1: 간단한 Generator 함수

def count_up_to(max_value):
    count = 1
    while count <= max_value:
        yield count  # 값 반환
        count += 1   # 다음 값으로 이동

# Generator 객체 생성
counter = count_up_to(5)

# 값을 하나씩 출력
for num in counter:
    print(num)

출력:

1
2
3
4
5

이 예제에서 count_up_to 함수는 yield를 통해 값을 하나씩 반환합니다. 한 번 호출될 때마다 함수의 상태가 유지되며, 다음 호출에서 이어서 실행됩니다. for 문을 사용하면 Generator에서 반환된 값들을 순차적으로 처리할 수 있습니다.

2.2. Generator 표현식

Generator는 리스트 컴프리헨션과 비슷한 형태로도 생성할 수 있습니다. 이 경우, [] 대신 ()를 사용하여 간결한 Generator 표현식을 작성할 수 있습니다.

예제 2: Generator 표현식

# 1부터 9까지의 제곱수를 생성하는 Generator 표현식
squares = (x**2 for x in range(1, 10))

# Generator에서 값을 하나씩 출력
for square in squares:
    print(square)

출력:

1
4
9
16
25
36
49
64
81

이 예제에서는 Generator 표현식을 사용하여 1부터 9까지의 제곱수를 생성합니다. () 안에 컴프리헨션 형태를 사용하여 간단하게 작성할 수 있으며, 메모리를 절약할 수 있습니다.

3. Generator의 작동 방식

3.1. next() 함수를 이용한 값 반환

Generator는 next() 함수를 이용해 값을 하나씩 반환할 수 있습니다. yield를 만나면 해당 값을 반환하고, 함수는 그 시점에서 멈춥니다. 이후 다시 호출되면 멈춘 지점에서 이어서 실행됩니다.

예제 3: next()로 Generator 제어

def simple_generator():
    yield 1
    yield 2
    yield 3

gen = simple_generator()

print(next(gen))  # 첫 번째 값 반환
print(next(gen))  # 두 번째 값 반환
print(next(gen))  # 세 번째 값 반환

출력:

1
2
3

이 예제에서 next(gen)을 호출할 때마다 simple_generator() 함수의 yield에서 값을 하나씩 반환하고, 함수는 그 지점에서 멈춥니다. 모든 값을 반환하면 StopIteration 예외가 발생합니다.

4. 무한 Generator 예시

무한한 데이터를 처리할 때 Generator를 사용하면 효율적입니다. 아래 예제는 끝없이 증가하는 수를 생성하는 무한 Generator입니다.

예제 4: 무한 Generator

def infinite_sequence():
    num = 0
    while True:
        yield num
        num += 1

# 무한 Generator 생성
gen = infinite_sequence()

# 첫 5개의 값만 출력
for _ in range(5):
    print(next(gen))

출력:

0
1
2
3
4

이 예제에서는 while True 루프를 사용하여 무한히 증가하는 값을 반환하는 Generator를 생성합니다. 하지만 Generator는 값을 필요한 만큼만 요청할 수 있기 때문에, 메모리 사용량을 걱정할 필요가 없습니다.

5. Generator를 사용하는 경우

  • 대규모 데이터 처리: 큰 리스트나 파일을 처리할 때 모든 데이터를 메모리에 로드하지 않고, 필요한 만큼만 값을 생성하여 처리하는 데 유리합니다.
  • 무한한 데이터 스트림 처리: 로그 처리, 실시간 데이터 처리 등 끝이 없는 데이터 스트림을 처리할 때 사용됩니다.
  • 성능 최적화: 반복문을 사용할 때 매번 계산할 필요가 없는 값을 미리 생성하여 성능을 높일 수 있습니다.