Python yield
완벽 가이드: 효율적인 데이터 처리와 제너레이터 사용법
Python을 배우다 보면 yield
라는 키워드를 만날 때가 있습니다. yield
는 함수의 실행을 잠시 멈추고, 데이터를 하나씩 반환하는 특별한 역할을 하는 키워드입니다. 특히 yield
를 사용하면 큰 데이터나 반복 작업을 더 효율적으로 처리할 수 있어요. 이번 글에서는 yield
의 개념을 이해하고, yield
를 활용해 제너레이터를 만드는 방법과 함께 실제 코드에서 유용하게 활용할 수 있는 예제를 소개합니다.
yield
란 무엇일까? - 제너레이터와의 관계
yield
는 Python의 함수에서 데이터를 반환하고 함수의 상태를 유지하는 키워드입니다. yield
를 만나면 함수는 그 시점에서 잠시 멈추고, 값을 반환한 후 필요할 때 다시 실행을 시작합니다. 이 yield
가 제너레이터(generator)를 만드는 핵심입니다.
제너레이터란?
제너레이터는 yield
를 사용해 만든 반복 가능한 객체입니다. 일반적인 함수는 값을 한 번에 모두 반환하는 반면, 제너레이터는 필요한 시점에 값을 하나씩 반환하여 메모리 사용을 줄입니다. 이 덕분에 데이터가 많아도 메모리에 부담 없이 다룰 수 있는 것이 큰 장점입니다.
기본 예제: yield
를 사용해 제너레이터 만들기
yield
를 사용해 기본적인 제너레이터 함수를 만들어보겠습니다. 이 함수는 1부터 n
까지의 숫자를 차례로 반환합니다.
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
# 제너레이터 호출
counter = count_up_to(5)
print(next(counter)) # 1
print(next(counter)) # 2
print(next(counter)) # 3
print(next(counter)) # 4
print(next(counter)) # 5
결과
1
2
3
4
5
설명
yield count
는count
값을 반환하고 함수의 상태를 유지합니다.next(counter)
를 호출할 때마다 함수가 중단된 곳부터 다시 시작하며, 다음 값을 반환합니다.count_up_to(5)
제너레이터는 1부터 5까지의 숫자를 순서대로 반환합니다.
yield
와 return
의 차이점 이해하기
함수에서 yield
대신 return
을 사용하면 제너레이터가 아니라 일반 함수가 됩니다. 일반 함수는 값을 모두 계산해 한 번에 반환하는 반면, yield
는 필요한 시점에 하나씩 값을 전달합니다.
def normal_function():
return 1
return 2 # 이 부분은 실행되지 않습니다
def generator_function():
yield 1
yield 2
# 결과 확인
print(normal_function()) # 1
for value in generator_function():
print(value) # 1, 2
결과
1
1
2
설명
normal_function()
은 1을 반환하고 함수가 끝납니다. 이후 코드는 실행되지 않습니다.generator_function()
은yield
를 통해 값을 순서대로 반환합니다. 제너레이터는for
문을 통해 각 값을 하나씩 출력할 수 있습니다.
yield
의 실제 활용 예제: 큰 데이터 처리하기
큰 데이터를 다룰 때 yield
는 메모리 사용을 최소화하는 데 매우 유용합니다. 예를 들어, 큰 파일을 한 줄씩 읽어들이는 제너레이터를 만들어보겠습니다.
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_text_file.txt"):
print(line)
설명
read_large_file
제너레이터는 파일을 한 줄씩 읽고, 각 줄을yield
를 통해 반환합니다.- 큰 파일을 한꺼번에 메모리에 올리지 않기 때문에 파일 크기와 상관없이 효율적으로 읽을 수 있습니다.
yield
를 이용한 무한 시퀀스 생성
일정한 패턴의 무한 시퀀스를 생성할 때도 yield
는 유용합니다. 아래 예제는 피보나치 수열을 생성하는 제너레이터입니다.
def fibonacci_sequence():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 피보나치 수열 출력
fibo_gen = fibonacci_sequence()
for _ in range(10):
print(next(fibo_gen))
결과
0
1
1
2
3
5
8
13
21
34
설명
fibonacci_sequence()
는 무한히 피보나치 수열을 생성합니다.next(fibo_gen)
를 호출할 때마다yield
로 인해 다음 피보나치 숫자를 반환합니다.- 무한 시퀀스를 생성할 때
yield
는 효율적이고 간결하게 코드를 작성할 수 있는 방법입니다.
yield from
으로 중첩된 제너레이터 처리하기
Python에서는 yield from
문법을 사용해 중첩된 제너레이터에서 값을 가져올 수 있습니다. 여러 제너레이터에서 데이터를 합쳐서 반환할 때 유용합니다.
def generator1():
yield "A"
yield "B"
def generator2():
yield from generator1()
yield "C"
yield "D"
# 실행 예시
for value in generator2():
print(value)
결과
A
B
C
D
설명
generator2
는yield from generator1()
을 통해generator1
의 값을 모두 반환한 후 자신의 값을 추가로 반환합니다.yield from
을 사용하면 중첩된 제너레이터에서 값을 한꺼번에 가져올 수 있어 코드가 간결해집니다.
실전 예제: 데이터 파이프라인에서 yield
활용하기
데이터를 여러 단계로 처리해야 할 때 yield
는 중간 결과를 순차적으로 전달해주므로 매우 유용합니다. 예를 들어, 데이터를 필터링하고 처리하는 파이프라인을 구성할 수 있습니다.
def data_generator(data):
for item in data:
yield item
def filter_data(data_gen, threshold):
for item in data_gen:
if item > threshold:
yield item
def process_data(filtered_data):
for item in filtered_data:
yield item * 2
# 데이터 생성 및 처리
data = [1, 5, 10, 15, 20]
data_gen = data_generator(data)
filtered_data = filter_data(data_gen, 10)
processed_data = process_data(filtered_data)
for item in processed_data:
print(item)
결과
20
30
40
설명
data_generator
는 데이터를 생성하고,filter_data
는 조건에 맞는 데이터만 필터링하며,process_data
는 필터링된 데이터에 처리를 적용합니다.- 각 단계에서
yield
를 사용하여 데이터를 필요한 만큼만 처리하고 전달하므로 메모리를 절약하면서 효율적으로 데이터를 다룰 수 있습니다.
요약: yield
의 장점과 활용법
Python에서 yield
는 메모리 효율적인 데이터 처리를 가능하게 해주며, 제너레이터를 통해 값이 필요할 때마다 순차적으로 데이터를 생성할 수 있습니다. 이를 통해 코드가 간결해지고, 큰 데이터를 다루거나 무한 반복 작업을 수행할 때 매우 유용합니다.
yield
는 특히 다음과 같은 상황에서 유용하게 활용됩니다:
- 큰 데이터를 처리할 때: 메모리 절약을 통해 효율적으로 데이터를 읽을 수 있습니다.
- 무한 반복 생성이 필요한 경우:
yield
를 사용해 무한 시퀀스를 간단히 구현할 수 있습니다. - 중첩된 데이터를 다룰 때:
yield from
을 사용해 중첩된 제너레이터를 간단히 처리할 수 있습니다.
'개발 > Python 스터디' 카테고리의 다른 글
[Python] `enumerate`로 간편하게 인덱스 추적하기: 인덱스와 값 모두 쉽게 관리하기 (0) | 2024.11.10 |
---|---|
[Python] 리스트 컴프리헨션과 메모리 절약: 더 빠르고 효율적인 코드 작성법 (1) | 2024.11.09 |
[Python] `*`와 `**`를 함께 사용하기: 위치 인자와 키워드 인자 활용법 (0) | 2024.11.07 |
[Python] `**` 문법으로 복잡한 코드를 간단하게: 딕셔너리 언패킹과 키워드 인자 사용법 (1) | 2024.11.06 |
[Python] `*` 문법 완벽 가이드: 함수 인자, 언패킹, 가변 인자까지 (2) | 2024.11.05 |