yield
구문을 통해 한번 호출될 떄마다 하나의 값만을 리턴일반적인 함수는 호출 시 모든 구문이 끝날 때까지 실행한 후, 모든 값을 리턴하고 종료되며, 종료 후에는 함수가 가지고 있던 모든 내부 함수나 로컬 변수는 메모리상에서 사라진다.
이 후 다시 같은 함수를 호출하면 모든 것이 처음부터 다시 새롭게 시작된다.
def square_numbers(nums):
result = []
for i in nums:
result.append(i * i)
return result
my_nums = square_numbers([1, 2, 3, 4, 5])
print(my_nums) # [1, 4, 6, 16, 25]
하지만, 제너레이터의 경우 모든 결과값을 반환하거나 메모리에 저장하지 않고, 제너레이터라는 오브젝트를 반환함으로써, 나중에 호출될 때마다 하나의 값만을 전달(yield)한다.
즉, 호출하더라도 값을 물어보기 전까지는 함수가 동작하지 않는다.
def square_numbers(nums):
for i in nums:
yield i * i
my_nums = square_numbers([1, 2, 3, 4, 5]) #1
print(my_nums) # <generator object square_numbers at 0x0000016B17E19EB0>
위와 같이 호출하더라도 제너레이터 오브젝트가 반환된다.
여기서 next()함수를 통해 값을 호출하면 제너레이터는 값을 하나만 반환한다.
print(next(my_nums)) # 1
여러번 반복하여 next()를 호출하면 다음과 같이 출력된다.
print(next(my_nums)) # 4
print(next(my_nums)) # 9
print(next(my_nums)) # 16
print(next(my_nums)) # 25
파이썬에서는 yield키워드를 통해 기존의 함수와는 다른 방식으로 결과 값을 얻을 수 있다.
yield가 호출되면 암시적으로 return이 호출되며, 한 번 더 실행하면 실행되었던 yield의 다음 코드가 실행된다. 이렇게 yield를 이용하여 결과값을 나누어 얻으면 성능 측면에서 큰 이점이 있다.
return 키워드를 사용할 경우 모든 결과값을 메모리에 올려놓아야 하는 반면, yield 키워드를 이용한 경우 결과 값 하나 씩만을 메모리에 올려둔다. 한정된 리소스를 효율적으로 활용해야 하는 경우 제너레이터를 이용하면 도움이 된다.
제너레이터를 반환하는 함수를 작성할 때, yield from 키워드를 사용하면 반복문 없이도 리스트를 제너레이터로 변환할 수 있다.
# 1. 반복문 사용
def generator():
for char in ['A,'B','C']:
yield char
# 2. yield from 사용
def generator():
yield from ['A,'B','C']
yield 키워드를 이용하지 않고 제너레이터 표현식을 통해서도 제너레이터를 만들 수도 있다.
방법은 리스트 컴프리핸션과 비슷하다. 차이점은 리스트 컴프리핸션은 대괄호를 사용하고, 제너레이터 컴프리핸션은 소괄호를 사용한다는 점이다.
lst1 = [x for x in range(5)] # 리스트 컴프리핸션
lst2 = (x for x in range(5)) # 제너레이터 컴프리핸션
print(lst1) # [0, 1, 2, 3, 4]
print(lst2) # <generator object <genexpr> at 0x00000227CC3259E0>
for x in lst2:
print(x, end = ' ') # 0 1 2 3 4
- 파이썬의 yield 키워드와 제너레이터(generator)
- 파이썬 - 제너레이터 (Generator) - schoolofweb.net
- 점프 투 파이썬