👌 기본적으로 AIFFEL FUNDIMENTALS 자료를 참고했습니다.
- In Python Wiki
"Generator functions allow you to declare a function that behaves like an iterator, i.e. it can be used in a for loop."
간략하게 요약하자면..
출처: https://bluese05.tistory.com/56
def generator(n):
i = 0
while i < n:
yield i
i += 1
for x in generator(5):
print x
>>>
0
1
2
3
4
🤟 코드 설명
1. for 문이 실행되며, 먼저 generator 함수가 호출된다.
2. 실행 중 while 문 안에서 yield 를 만나게 된다. 그러면 return 과 비슷하게 함수를 호출했던 구문으로 반환하게 된다. 여기서는 첫번재 i 값인 0 을 반환하게 된다. 하지만 반환 하였다고 generator 함수가 종료되는 것이 아니라 그대로 유지한 상태이다.
3. x 값에는 yield 에서 전달 된 0 값이 저장된 후 print 된다. 그 후 for 문에 의해 다시 generator 함수가 호출된다.
4. 이때는 generator 함수가 처음부터 시작되는게 아니라 yield 이후 구문부터 시작되게 된다. 따라서 i += 1 구문이 실행되고 i 값은 1로 증가한다.
5. 아직 while 문 내부이기 때문에 yield 구문을 만나 i 값인 1이 전달 된다.
6. x 값은 1을 전달 받고 print 된다. (이후 반복)
위 티스토리 코드 설명이 너무 깔끔하고 이해하기 쉬워 가지고 왔습니다!!
my_list = ['a','b','c','d']
# 인자로 받은 리스트를 가공해서 만든 데이터셋 리스트를 리턴하는 함수
def get_dataset_list(my_list):
result_list = []
for i in range(2):
for j in my_list:
result_list.append((i, j))
print('>> {} data loaded..'.format(len(result_list)))
return result_list
for X, y in get_dataset_list(my_list):
print(X, y)
>>>
>> 1 data loaded..
>> 2 data loaded..
>> 3 data loaded..
>> 4 data loaded..
>> 5 data loaded..
>> 6 data loaded..
>> 7 data loaded..
>> 8 data loaded..
0 a
0 b
0 c
0 d
1 a
1 b
1 c
1 d
my_list = ['a','b','c','d']
# 인자로 받은 리스트로부터 데이터를 하나씩 가져오는 제너레이터를 리턴하는 함수
def get_dataset_generator(my_list):
result_list = []
for i in range(2):
for j in my_list:
yield (i, j) # 이 줄이 이전의 append 코드를 대체했습니다
print('>> 1 data loaded..')
dataset_generator = get_dataset_generator(my_list)
for X, y in dataset_generator:
print(X, y)
>>>
0 a
>> 1 data loaded..
0 b
>> 1 data loaded..
0 c
>> 1 data loaded..
0 d
>> 1 data loaded..
1 a
>> 1 data loaded..
1 b
>> 1 data loaded..
1 c
>> 1 data loaded..
1 d
>> 1 data loaded..
위 두 코드의 차이를 아시겠나요?? 코드결과를 보면 단순For문은 get_dataset_list() 함수 안의 로직을 전부 실행난 다음 Return 한 result_list를 실행시킵니다. 하지만 Generator는 get_dataset_generator() 전부 실행시키는 것이 아닌 yield 지점에서 멈춘 후 실행되는 것을 볼 수 있습니다.
Generator의 장점???
- memory를 효율적으로 사용할 수 있다.
- Lazy evaluation(계산 값이 필요할때 까지 계산을 늦추는 효과)
1. Memory의 효율성
import sys
sys.getsizeof( [i for i in xrange(100) if i % 2] ) # list
>> 536
sys.getsizeof( [i for i in xrange(1000) if i % 2] )
>> 4280
sys.getsizeof( (i for i in xrange(100) if i % 2) ) # generator
>> 80
sys.getsizeof( (i for i in xrange(1000) if i % 2) )
>> 80
위의 코드결과를 보면 Generator의 경우 list의 사이즈와 상관없이 사이즈가 일정한 것을 볼 수 있다. (참고로 [i for i in xrange(100) if i % 2]는 list comprehension이고 (i for i in xrange(100) if i % 2)는 generator comprehension 이다.)
"list 는 list 안에 속한 모든 데이터를 메모리에 적재하기 때문에 list의 크기 만큼 차지하는 메모리 사이즈가 늘어나게 된다. 하지만 generator 의 경우 데이터 값을 한꺼번에 메모리에 적재 하는 것이 아니라 next() 메소드를 통해 차례로 값에 접근할 때마다 메모리에 적재하는 방식이다."
2. Lazy evlaution
Lazy evaluation 즉 계산 결과 값이 필요할 때까지 계산을 늦추는 효과를 볼 수 있다.
단순 For문과 Generator 비교 의 Lazy evaluation의 예시.
마지막으로 정리하자면 가장 중요한점은 Generator를 사용하면 메모리를 최대한 효율적으로 사용할 수 있다는 짐이라고 생각한다. 대용량의 데이터를 사용할 수록 Generator를 사용해야 한다는 생각이 든다....
[참고 자료]
- 저작권 문제가 있을 시 해당 게시물을 즉각 수정 및 삭제 조치하겠습니다.