얼마 전 시험을 보면서 Python에 yield 키워드가 있다는 것을 알게 되었다.
그래서 오늘은 yield 키워드가 무엇이고, 왜 사용하는지, 그리고 어떻게 사용하는지 간단하게 알아보려고 한다.
1. yield 키워드가 무엇인가?
yield 키워드는 return 키워드처럼 함수 내부에서 값을 반환할 때 사용되는 키워드이다.
일반적인 함수에서는 return 을 만나면 값을 반환하고 함수를 완전히 종료한다. 반면, yield 를 사용한 함수는 값을 반환한 후에도 함수의 상태를 그대로 유지한 채 잠시 멈춘다. 그리고 해당 함수가 다음에 다시 호출될 때 멈췄던 지점부터 실행을 재개하게 된다.
즉, return 이 함수의 종료 및 값 반환 역할이라면, yield 는 함수의 일시정지 및 값 반환 역할을 수행한다는 차이가 있다.
간단한 예제를 살펴보자. 1, 2, 3을 순서대로 반환하는 함수를 yield 키워드를 이용하여 구현하면 다음과 같다.
def yield_123():
yield 1
yield 2
yield 3
for 반복문을 통해 위 함수를 호출하면, 다음과 같은 결과가 출력된다.
for i in yield_123():
print(i)
1
2
3
2. yield 키워드는 왜 사용하는가?
위 예제의 결과만 보면 return 을 사용한 함수와 별 차이가 없어보인다.
실제로 yield 대신 return 을 사용하여 함수를 구현해도 같은 결과가 나온다.
def return_123():
return [1, 2, 3]
for i in return_123():
print(i)
1
2
3
그러면 yield 키워드는 왜 사용하는 걸까?
앞서 언급했듯이, yield 키워드는 함수의 일시정지 및 값 반환 역할을 수행한다.
만약 위의 예제에서 1부터 3까지가 아니라 1부터 매우 큰 값까지의 수를 하나씩 반환해야 하는 상황이라고 가정해보자.
우선 return 으로 함수를 구현하면 다음과 같다.
def return_from_1_to_n(n):
result = []
i = 1
while i <= n:
result.append(i)
i += 1
return result
n = 100 # n이 매우 큰 수라면 문제가 될 수 있음
for i in return_from_1_to_n(n):
print(i)
그런데 함수를 이렇게 구현하면, 함수가 종료될 때 1부터 n까지의 모든 수가 담긴 리스트가 한번에 반환될 것이다.
즉, n개의 수를 모두 메모리에 저장하기 때문에 큰 메모리 공간을 차지하게 된다.
만약 n이 매우 큰 수라면 메모리 측면에서 문제가 될 수 있는 상황이다.
반면, yield 로 함수를 구현한 yield_from_1_to_n 함수는 호출 즉시 n개의 수를 만들지 않는다. 대신, for 반복문과 같이 값이 필요할 때마다 yield 를 통해 수를 하나씩 생성하여 전달한다.
def yield_from_1_to_n(n):
result = []
i = 1
while i <= n:
yield i
i += 1
return result
n = 100 # n이 매우 큰 수여도 문제 없음
for i in yield_from_1_to_n(n):
print(i)
즉, yield 를 통해 구현하면 메모리에 모든 데이터를 한번에 올릴 필요가 없어지므로, 대용량 데이터를 처리할 때 매우 효율적이다.
3. Generator
지금까지 yield 키워드의 사용 방법에 대해 아주 간단하게 알아봤는데, yield 키워드를 더 찾아보다보면 generator라는 개념도 등장한다.
이제 yield 키워드와 관련이 있는 generator가 무엇인지도 함께 살펴보자.
파이썬의 generator는 한번에 하나씩 값을 만들어내는 특별한 객체이다. (또는 반복자(iterator)라고 한다)
모든 값을 메모리에 저장해두고 사용하는 list와 달리, generator는 값이 필요한 시점에 그때그때 값을 계산해서 반환한다.
그리고 앞서 살펴본 yield 키워드는 generator를 만드는 도구에 해당한다.
함수 안에 yield 키워드가 포함되면, 그 함수는 평범한 함수가 아니라 제너레이터 함수가 된다. 그리고 이 함수를 호출하면 generator 객체가 반환된다.
다음 예제를 통해서도 generator 객체가 반환되는 것을 확인할 수 있다.
def yield_test():
for i in range(5):
yield i
print(i, "번째 호출")
print(yield_test())
<generator object yield_test at 0x1030f6a80>
4. 사용법
(1) __next__() 함수를 통한 호출
def yield_test():
for i in range(3):
yield i
print(i, "번째 호출")
t = yield_test()
print(t.__next__())
print("==========")
print(t.__next__())
print("==========")
print(t.__next__())
print("==========")
0
==========
0 번째 호출
1
==========
1 번째 호출
2
==========
for 반복문으로 호출할 때와 비교하면, 결과에 약간의 차이가 있다. for 반복문이 종료될 때 출력이 한번 더 수행되는 것을 보면 약간의 로직 차이가 있는 듯 하다.
def yield_test():
for i in range(3):
yield i
print(i, "번째 호출")
for i in yield_test():
print(i)
print("==========")
0
==========
0 번째 호출
1
==========
1 번째 호출
2
==========
2 번째 호출
만약 다음과 같이 __next__()_ 함수를 지정한 횟수를 초과하여 호출한다면 오류가 발생한다.
def yield_test():
for i in range(3):
yield i
print(i, "번째 호출")
t = yield_test()
print(t.__next__())
print("==========")
print(t.__next__())
print("==========")
print(t.__next__())
print("==========")
print(t.__next__()) # 오류 발생
print("==========")
0
==========
0 번째 호출
1
==========
1 번째 호출
2
==========
2 번째 호출
Traceback (most recent call last):
File "/Users/infikei/InfikeiProjects/github/algorithm/tmp-folder/test112.py", line 22, in <module>
print(t.__next__()) # 오류 발생
~~~~~~~~~~^^
StopIteration
(2) yield from
예를 들어 다음과 같이 list의 원소를 하나씩 차례대로 반환하는 generator 함수를 작성해야 하는 경우가 있을 수 있다.
def yield_from_list():
for i in ["Alpha", "Bravo", "Charlie"]:
yield i
yield from 키워드를 사용하면 for 반복문을 사용하지 않고 다음과 같이 코드를 간편하게 작성할 수 있게 된다.
def yield_from_list():
yield from ["Alpha", "Bravo", "Charlie"]
(3) Generator를 이용한 무한 데이터 생산
generator를 사용하면 데이터를 무한하게 생성하는 함수도 구현할 수 있다.
def yield_infinite_abc():
while True:
yield "Alpha"
yield "Bravo"
yield "Charlie"
for i in yield_infinite_abc():
print(i)
# 또는 yield from 키워드를 사용할 수도 있음
def yield_infinite_abc():
while True:
yield from ["Alpha", "Bravo", "Charlie"]
for i in yield_infinite_abc():
print(i)
Alpha
Bravo
Charlie
Alpha
Bravo
Charlie
Alpha
Bravo
Charlie
Alpha
^C
Traceback (most recent call last):
File "/Users/infikei/InfikeiProjects/github/algorithm/tmp-folder/test112.py", line 6, in <module>
print(i)
~~~~~^^^
KeyboardInterrupt
(4) Generator Comprehension
generator를 만드는 또 다른 방법으로 generator comprehension이 있다.
사용 방법은 list comprehension과 거의 유사한데, list comprehension은 대괄호를 사용하고 generator comprehension은 소괄호를 사용한다는 차이가 있다.
gen_abc = (x for x in ["Alpha", "Bravo", "Charlie"])
print(gen_abc)
for x in gen_abc:
print(x)
<generator object <genexpr> at 0x102cca380>
Alpha
Bravo
Charlie
5. 참고 자료
'Python' 카테고리의 다른 글
| uv 설치하고 프로젝트 생성하기 (0) | 2025.09.14 |
|---|---|
| Python 형 변환 간단히 정리 (0) | 2022.04.24 |