yield
yield 는 함수 안에서 값을 반환하지만, 함수의 실행 상태를 유지한 채로 반환을 중단한다.
yield를 만나면, 값을 반환하고, 그 함수는 "일시정지" 한 상태가 되어 나중에 다시 호출되면 그 지점부터 실행을 이어나가게 된다.
yield 는 제너레이터 함수를 정의하거나 이터레러블 객체에 yield를 위임하는 데 사용되며, 제너레이터 함수는 호출될 때 제너레이터 객체를 반환한다. 이 객체는 이터레이터 처럼 next()를 호출할 때마다 값을 하나씩 반환한다.
def yield_test():
yield 1
yield 2
yield 3
gen = yield_test()
print(type(gen)) # <class 'generator'>
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
print(next(gen)) # StopIteration...
yield 함수는 generator 타입이며, next 함수로 iterable 한 객체를 호출하여 값을 가져올 수 있다. 일반적인 함수의 경우 값을 return 받을 때 함수를 종료하고, 값을 반환하는 형태를 취하지만 yield의 경우 generator 형태로 값을 순차적으로 반환해주는 형태로 선언한다.
return 과의 차이
- return : 함수가 실행되고 완료하고 값을 반환하며, 그 후 함수의 상태는 완전히 소멸
- yield : 함수를 호출할 때마다 값을 하나씩 반환하고, 함수의 실행 상태를 저장한다. 나중에 함수가 다시 호출되면, 저장된 상태에서 이어서 실행한다.
예를 들면 이런 식이다
def data_generator():
for data in ['A', 'B', 'C', 'D', 'E']:
yield data # 데이터 하나씩 생성
print(f"yield 다음 줄에서 {data}출력")
for data in data_generator():
print(f"yield 문을 만나면 {data} 는 여기로 옵니다")
# yield 문을 만나면 A 는 여기로 옵니다
# yield 다음 줄에서 A출력
# yield 문을 만나면 B 는 여기로 옵니다
# yield 다음 줄에서 B출력
# ...
이는 말 그대로 yield문에서 "일시정지" 된 것이며, 함수가 다시 호출되면 일시정지 된 지점 다음부터 실행한다.
예제 : 주어진 list 에서 짝수를 반환하는 함수
- yield 를 이용할 때 :
numbers_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def sol(nums) :
for num in nums :
if num %2 == 0 :
yield num
for n in sol(numbers_list) :
print(n, end = "\n")
- list 를 이용할 때 :
numbers_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def sol(nums):
result = []
for num in nums:
if num % 2 == 0:
result.append(num)
return result
for n in sol(numbers_list):
print(n, end="\n")
두 방법 모두 시간복잡도는 O(n)으로 동일하나, 제너레이터는 메모리 사용량이 적고, 지연 평가를 통해 필요할 때만 값을 생성하므로 더 효율적이다.
데이터셋의 크기가 작거나, 전체 결과를 한 번에 처리할 필요가 있는 경우에는 일반 리스트를,
데이터셋의 크기가 크고 메모리 사용량을 최소화 하고자 할 때는 제너레이터가 더 나은 선택임을 알 수 있다.
'알고리즘' 카테고리의 다른 글
[코딩테스트 합격자 되기 08] 해시 Q&A (0) | 2024.10.07 |
---|---|
[코딩테스트 합격자 되기 08] 해시 (0) | 2024.10.04 |
[코딩테스트 합격자 되기 07] 큐 (0) | 2024.09.23 |
[백준] 1914 하노이탑 (0) | 2024.09.22 |
[코딩테스트 합격자 되기 + ] 재귀 (0) | 2024.09.22 |