파이썬 특수 문법(데코레이터, 이터레이터등) - . 파이썬 제너레이터 (Generator)

21. 파이썬 제너레이터 (Generator)

  • iterator를 만들어주는 기능
  • generator를 이해하기 위해 yield 키워드를 이해하자

21.1. yield 를 통해 generator를 이해하자

In [3]:
def str_data():
    data = "hi Dave"
    for item in data:
        return item
In [9]:
# str_data 는 함수
str_data
Out[9]:
<function __main__.str_data>
In [12]:
# str_data() 를 호출하면 함수가 실행되고 종료된다.
str_data()
Out[12]:
'h'
In [17]:
# str_data() 함수를 기반으로 iterator 만들기
char = iter(str_data())
In [11]:
# char 는 iterator
char
Out[11]:
<str_iterator at 0x105ff3e10>
In [5]:
next(char)
Out[5]:
'h'
In [6]:
next(char)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-6-7e9e25a1b8ba> in <module>()
----> 1 next(char)

StopIteration: 


생각해보기1
1. 위 코드에서 에러가 나는 이유를 생각해보자

이미 첫 next() 호출시, iterator인 char는 끝나버렸다!

yield란?

  • return 은 결과값을 리턴하고, 함수를 종료
  • yield 는 yield라고 적은 곳에서 잠시 함수 실행을 멈추고 호출한 곳에 값을 전달
    • 해당 함수는 현재 실행된 상태를 계속 유지
    • 따라서, 다시 해당 함수를 호출하면 현재 실행된 상태를 기반으로 다음 코드를 실행함
In [13]:
def str_data():
    data = "hi Dave"
    for item in data:
        yield item
In [14]:
# str_data 는 함수
str_data
Out[14]:
<function __main__.str_data>
In [24]:
# str_data() 를 호출하면 generator 객체가 생성된다.
str_data()
Out[24]:
<generator object str_data at 0x1060c52b0>
In [25]:
# str_data() 함수를 기반으로 iterator 만들기
char = iter(str_data())
In [26]:
next(char)
Out[26]:
'h'


In [27]:
next(char)
Out[27]:
'i'
In [28]:
print (next(char))
print (next(char))
print (next(char))
 
D
a
생각해보기2
1. 위 코드에서 이번에는 에러가 안나는 이유를 생각해보자

iterator인 char는 현재 실행된 상태를 계속 유지하기 때문에 다음 next() 호출시, 현재 상태 기반 다음 코드를 진행

21.2. Generator Expression

  • Generator Comprehension 이라고도 함
  • List Comprehension과 형식 유사
    • List Comprehension은 앞뒤를 [ ] 대괄호로 표현
    • Generator Expression ( ) 둥근 괄호로 표현
  • 실제 컬렉션 데이터를 리턴하지 않고, 표현식만 유지
    • yield 방식으로 실제 호출할 때 관련 데이터 리턴(Lazy Operation)
In [117]:
# list comprehension 예
square_data = [num ** 2 for num in range(5)]
In [118]:
print( type(square_data))
print (square_data)
print (sum(square_data))
<class 'list'>
[0, 1, 4, 9, 16]
30
In [119]:
print (sum(square_data))
print (sum(square_data))
print (sum(square_data))
30
30
30


In [120]:
# generator expression 예1
square_data = (num ** 2 for num in range(5))
In [121]:
print (type(square_data))
print (square_data)
print (sum(square_data))   # <--- 실제 사용될 때 관련 데이터 리턴(Lazy Operation)
<class 'generator'>
<generator object <genexpr> at 0x1060c5a40>
30
In [122]:
# 위 sum() 함수에서 제너레이터 모든 데이터를 다 리턴하였으므로, 더이상 리턴할 데이터가 없음
print (sum(square_data))
0
In [130]:
# generator expression 예3
square_data = (num ** 2 for num in range(5))
In [131]:
# 두 개의 데이터만 순회
for num in range(2):
    print (next(square_data))
0
1
In [132]:
# 나머지 데이터를 순회
for num in square_data:
    print (num)
4
9
16
In [129]:
for num in lst:
    print(num, end=' ')
    
print()
    
for num in lst:
    print(num, end=' ')
0 1 4 9 16 
0 1 4 9 16