본문 바로가기
python

[python]파이썬 - 제너레이터(Generator)

by skysline 2023. 1. 25.
반응형

iterable & iterator

  • iterable 객체: 반복 가능한 객체(list,dict,set,tuple,str,range...)
  • iterator 객체: 값을 차례대로 꺼낼 수 있는 객체
    • 다 꺼내면 사라진다.
    • 꺼낼때 데이터를 메모리에 생성해주는 방식
 
  • iter 함수
    • iterable 객체를 iterator 객체로 변환한다.
 
 
lst = [1,2,3]
iterator = iter(lst)
type(iterator)
 
list_iterator
 
  • for 문은 iterable , iterator 객체를 모두 반복해준다.
 
 
 
for i in lst:
    print(i)
 
1
2
3
 
 
 
for i in iterator: # iterator 객체는 다꺼내면 사라진다.
    print(i)
 
 
  • next 함수
    • iterator 객체를 순서대로 하나씩 꺼내주는 함수.
 
 
 
lst = [1,2,3]
iterator = iter(lst)

print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator)) # 더이상 꺼낼수 없어 에러 발생
 
 
 
 
 
iterator = zip([1,2,3][4,5,6])
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator)) # 더이상 꺼낼수 없어 여기서 에러 발생
 
 
 
 
 
iterator = zip([1,2,3],[4,5,6])
for n1,n2 in iterator:
    print(n1,n2)
for n1,n2 in zip([1,2,3],[4,5,6]):
    print(n1,n2)
 
1 4
2 5
3 6
 
  • next 함수는 iterator 객체만 꺼낼수 있다.
 
next([1,2,3])
 
 
 

Generator란?

  • iterator를 생성해주는 표현식
  • iterator와 같은 동작을 하는 객체
 

소괄호를 이용한 제너레이터 객체 만들기

 
gen = (x for x in range(3))
type(gen)
 
generator
 
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen)) # 여기서 에러발생~~다 꺼냈으니까!
 
map_obj = map(lambda x: x , range(3)) # (x for x in range(3))
print(next(map_obj))
print(next(map_obj))
print(next(map_obj))
print(next(map_obj)) # 다 꺼내서 에러발생
 
 
 
  • 메모리 사이즈 비교
 
 
 
import sys

gen = (x for x in range(1000000))
lst = list(range(1000000))

sys.getsizeof(gen) , sys.getsizeof(lst) # 바이트 단위로 반환
 
(128, 9000120)
 
# sys.getsizeof?
 
%%timeit
lst = list(range(1000000))
tmp = []
for data in lst:
    tmp.append(data)
 
10 loops, best of 5: 118 ms per loop
 
%%timeit
gen = (x for x in range(1000000))
tmp = []
for data in gen:
    tmp.append(data)
 
10 loops, best of 5: 150 ms per loop
 
소괄호를 이용해서 0 ~ 300까지의 숫자들 중에서 3의 배수만 꺼내는 제너레이터 객체를 생성하시오.
 
gen = (x for x in range(3,301,3))
for i in gen:
    if i > 10:
        break
    print(i)
 
3
6
9
 
소괄호를 이용해서 다음의 리스트의 요소들의 제곱근을 꺼내는 제너레이터를 생성하시오.
lst = [20,40,60,80,34,90,10]
 
lst = [20,40,60,80,34,90,10]
gen = ( x**0.5 for x in lst)
for i in gen:
    print(i)
 
4.47213595499958
6.324555320336759
7.745966692414834
8.94427190999916
5.830951894845301
9.486832980505138
3.1622776601683795
 

함수를 이용한 제너레이터 객체 만들기

  • yield 문을 이용하면 된다.
def gen_func():
    yield 1
    yield 2
    yield 3
 
gen = gen_func()
type(gen)
 
generator
 
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen)) # 여기서 에러발생
 
def gen_func(num):
    for i in range(num):
        yield i
 
gen = gen_func(5)
type(gen)
 
generator
for n in gen:
    print(n)
 
 
리스트를 입력 받아 None 값을 제외하고 꺼내주는 제너레이터를 생성하시오
yield 문을 이용해서 함수로 만드세요.

ex)
lst = ["사과","딸기",None,"참외",None,"수박"]

gen = gen_list(lst)
for s in gen:
    print(s)

Output:
사과
딸기
참외
수박
 
 
 
lst = ["사과","딸기",None,"참외",None,"수박"]

def gen_list(lst):
    for item in lst:
        if item is not None:
            yield item

gen = gen_list(lst)
for s in gen:
    print(s)
 
사과
딸기
참외
수박
 
enumerate 함수 구현해보기
yield 문을 이용하여 gen_enumerate 이름의 함수로 enumerate 함수를 구현해보자.
enumerate 함수가 없다는 가정하에 만들어보자.
ex)
def gen_enumerate(param):
    pass

lst = [50,70,80]
for i,item in gen_enumerate(lst):
    print(i,item)
Output:
0 50
1 70
2 80
 
 
 
def gen_enumerate(param):
    length = len(param)
    for i in range(length):
        yield i,param[i]

lst = [50,70,80]
for i,item in gen_enumerate(lst):
    print(i,item)
 
0 50
1 70
2 80
 
def gen_enumerate(lst):
    length = len(lst)
    return ( (i,lst[i]) for i in range(length))

lst = [50,70,80]
gen = gen_enumerate(lst)
for i , item in gen:
    print(i,item) 
 
0 50
1 70
2 80
 
zip 함수 구현해보기
yield 문을 이용하여 gen_zip 이름의 함수로 zip 함수를 구현해보자.
2개 이상의 리스트가 인수로 들어 온다고 가정하자.
인수로 들어오는 리스트의 길이는 편의상 같은 길이가 들어온다고 가정하자.
zip 함수가 없다는 가정하에 만들어보자.
ex)
def gen_zip(*args):
    pass

list1 = [50,70,80]
list2 = [105,320,380]

for item1,item2 in gen_zip(list1,list2):
    print(item1,item2)
Output:
50 105
70 320
80 380
 
def gen_zip(*args):
    length = len(args[0])
    for i in range(length):
        yield [ lst[i] for lst in args]
        # tmp = []
        # for lst in args:
        #     tmp.append(lst[i])
        # yield tmp
list1 = [50,70,80]
list2 = [105,320,380]
list3 = [106,330,390]

for item1,item2,item3 in gen_zip(list1,list2,list3):
    print(item1,item2,item3)
 
50 105 106
70 320 330
80 380 390
 
  • yield from 이용해서 간단히 제너레이터 만들기
def gen_func(num):
    yield from range(num) 
 
gen = gen_func(5)
for n in gen:
    print(n)
n = 5
gen = (i for i in range(n))
def gen_func(lst):# 데이터 들이 담긴 리스트를 받는다.
    tmp = []
    for i in lst:
        tmp.append(i ** 2)

    yield from tmp

lst = list(range(10))
gen = gen_func(lst)

for i in gen:
    print(i)
0
1
4
9
16
25
36
49
64
81
반응형

댓글