[Python] Generators

미남잉·2025년 2월 17일
0

Advanced Python

목록 보기
3/10

유튜브 강의와 GPT로 정리하였습니다.

출처: 유튜브 - Generators - Advanced Python Tutorial #3

1. Generator란?

일반 함수와의 차이점

일반적인 함수는 호출되면 모든 코드를 한 번에 실행하고 끝난다.
하지만 Generator 함수는 yield를 사용하여 실행을 중간에 멈추고, 다시 호출하면 멈춘 지점부터 실행을 이어갈 수 있음.

장점

  • 메모리 효율적: 한 번에 하나의 값만 메모리에 올려서 대용량 데이터 처리에 유리.
  • 이터레이터처럼 사용 가능: next()를 호출하여 한 번에 하나의 값을 가져올 수 있음.
  • 무한 시퀀스 처리 가능: 리스트와 달리 무한 반복이 가능하여 CPU와 메모리 낭비 방지.

예제: 간단한 Generator

def my_generator():
    print("Start")
    yield 1
    print("Step 2")
    yield 2
    print("Step 3")
    yield 3
    print("End")

gen = my_generator()  # Generator 객체 생성

print(next(gen))  # 첫 번째 yield 실행
print(next(gen))  # 두 번째 yield 실행
print(next(gen))  # 세 번째 yield 실행
print(next(gen))

실행 과정

Start
1
Step 2
2
Step 3
3
End
Traceback (most recent call last):
  ...
StopIteration

동작 설명

  • next(gen) 호출 → "Start" 출력 후 yield 1 실행 → 1 반환 후 멈춤.
  • next(gen) 호출 → "Step 2" 출력 후 yield 2 실행 → 2 반환 후 멈춤.
  • next(gen) 호출 → "Step 3" 출력 후 yield 3 실행 → 3 반환 후 멈춤.
  • next(gen) 호출 → "End" 출력 후 더 이상 yield가 없으므로 StopIteration 예외 발생.

3. next() 함수

  • next()는 Generator를 한 단계 진행하여 yield 값을 반환하는 역할.
  • Generator에 더 이상 yield 값이 없으면 StopIteration 예외가 발생.

예제: next() 사용

def simple_gen():
    yield "A"
    yield "B"
    yield "C"

gen = simple_gen()

print(next(gen))  # A
print(next(gen))  # B
print(next(gen))  # C
print(next(gen))  # StopIteration 발생

4. Generator의 장점

  • 메모리 효율적
    - 한 번에 모든 데이터를 생성하지 않고 필요할 때마다 값을 반환.
    - 대량의 데이터를 처리할 때 리스트보다 훨씬 적은 메모리 사용.

  • 무한 시퀀스 처리 가능
    - while True를 이용해 무한 루프를 생성 가능.
    - 리스트는 크기가 제한되지만, Generator는 필요한 값만 계산해서 반환하므로 효율적.

예제: 무한 숫자 Generator

def infinite_numbers():
    num = 1
    while True:
        yield num
        num += 1  # 계속 증가

gen = infinite_numbers()

print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

=> 무한히 실행 가능

리스트(range())를 사용하면 메모리가 한계에 도달하지만, Generator는 메모리 낭비 없이 값을 하나씩 생성 가능.

5. Generator 표현식 (Generator Comprehension)

Python의 리스트 컴프리헨션(List Comprehension) 과 유사한 방식으로 Generator를 만들 수도 있음.

리스트 vs Generator 표현식

# 리스트 컴프리헨션 (메모리를 차지함)
lst = [x * 2 for x in range(10)]
print(lst)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Generator 표현식 (메모리 효율적)
gen = (x * 2 for x in range(10))
print(next(gen))  # 0
print(next(gen))  # 2
print(next(gen))  # 4
  • 리스트 컴프리헨션은 모든 값을 한 번에 메모리에 저장
  • Generator 표현식은 필요할 때만 값을 생성하여 메모리 사용량을 절약함

6. yield from 키워드 (서브 제너레이터)

여러 개의 Generator를 연결할 때 yield from을 사용하면 더 간결하게 코드 작성 가능.

예제: yield from을 사용한 Generator

def sub_generator():
    yield 1
    yield 2
    yield 3

def main_generator():
    yield from sub_generator()  # sub_generator의 모든 값을 yield
    yield 4
    yield 5

gen = main_generator()

for value in gen:
    print(value)

실행 결과

1
2
3
4
5
  • yield from을 사용하면 중첩된 Generator 값을 간단하게 반환 가능
  • for 루프에서 직접 yield를 호출하지 않아도 모든 값을 자동으로 가져옴

7. Generator 실전 예제

예제: 대용량 파일 한 줄씩 읽기

일반적으로 readlines()를 사용하면 전체 파일을 한 번에 읽어 메모리를 많이 차지하지만, Generator를 사용하면 한 줄씩 읽을 수 있어 메모리 절약 가능

def read_large_file(filename):
    with open(filename, "r") as file:
        for line in file:
            yield line.strip()  # 한 줄씩 반환

for line in read_large_file("large_data.txt"):
    print(line)  # 한 줄씩 출력
  • 파일 크기에 관계없이 한 줄씩 처리하여 메모리 낭비를 방지.
  • yield를 사용하여 필요할 때마다 줄을 읽어오기 때문에 메모리 사용량이 일정.

결론

개념설명
yieldGenerator에서 상태를 유지하면서 값을 반환
next()Generator의 다음 yield까지 실행
yield from다른 Generator 또는 Iterable의 모든 값을 가져오기
Generator 표현식()를 사용하여 메모리를 절약하면서 값 생성
  • Generator는 리스트보다 메모리 효율적이며 필요할 때만 값을 생성
  • next()를 사용해 값을 하나씩 생성하면서 사용할 수 있음
  • yield from을 사용하면 중첩된 Generator를 간결하게 처리 가능
  • 무한 루프(while True)나 대용량 데이터 처리에 최적화된 방식
profile
Computer Vision Engineer

0개의 댓글

관련 채용 정보