프로그래밍/PYTHON

python - Yield, Generator

aiemag 2021. 2. 10. 23:48
반응형

generator에 대해서 정리를 합니다.

 

 

generator의 정의는 generator iterator를 반환하는 함수입니다.

 

generator iterator의 특징은 

- generator iterator는 일반 iterator와 유사하지만 generator에서 yield 구문을 통하여 동작

- generator iterator는 iterator를 사용하는 모든 환경을 대체 가능

 

generator의 장점은

- iterator에 비해 메모리를 적게 사용

- lazy evaluation 으로 동작

 

 


generator에 사용되는 yield에 대한 정리입니다.

 

Yield

generator가 yield를 만나면 그 상태를 보존하고 있다가, 다시 generator가 호출되면 이어서 수행

yield는 generator에서 값을 반환하거나 값을 입력받는 기능을 수행

 

다음은 yield 사용 code입니다

 

3 line의 gen1()은 호출될 때마다 각 yield가 호출하는 값을 return 하게 됩니다.

 

8 line의 gen2()은 호출될 때마다 yield v 의 값을 return 하게 됩니다.

 

또한, 22 line의 generator iterator인 g2는 send를 통하여 값을 전달할 수 있는데,

 

12 line의 code를 보면 send로 gen2() 호출 시,  yield에 값이 먼저 전달이 되고 좌측 v에 값을 저장한 뒤, yield는 우측의 v값을 return 하게 됩니다.

next로 gen2() 호출 시, yield는 우측의 v 값을 return 하고 좌측에 None 값을 저장하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/python3
 
def gen1():
    yield 1
    yield 2
    yield 3
 
def gen2():
    v = 1
 
    while True:
        v = yield v
        print("-----------")
        print("v : ", v)
 
def main():
    print("test1")
    for g in gen1():
        print(g) 
 
    print("test2")
    g2 = gen2()
    print(next(g2))   
    print(g2.send(3))   
    print(g2.send(5))   
    print(next(g2))   
 
if __name__ == "__main__":
    main()
cs

 

출력 결과입니다.

 

gen1()의 generator iterator를 for문을 이용하여 출력한 결과 1,2,3 이 출력됩니다.

gen2()의 generator iterator에서 next, send, send, next를 이용한 결과 1,3,5,None이 출력됩니다.

 

 


Iterator와 Generator iterator와의 비교

 

다음은 sample code 입니다.

 

code를 실행하면 73, 74 line에서 test1() 과 test2()를 실행시킵니다.

 

test1()은 gen1()으로부터 얻은 list의 iterator를 test 합니다.

 

test2()은 gen2()로부터 얻은 generator iterator를 test 합니다.

 

10번의 반복 수행 후 평균 값을 얻기 위해 test_more라는 decorator를 만들고 이용하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/python3
 
import time
 
def gen1(count):
    g_list = []
    for i in range(count):
        g_list.append(i)     
 
    return g_list
 
 
def gen2(count):
    for i in range(count):
        yield i
 
 
def test_more(f):
 
    def inner(*args, **kwargs):
 
        count = 10
        init_t, process_t, total = 000
 
        for i in range(count):
            init_t_, process_t_, total = f(*args, **kwargs)
            init_t += init_t_
            process_t += process_t_
 
        print("%s average - init time : %s, process time : %s, total : %s\n" % 
            (f.__name__, init_t/count, process_t/count, total/count))
 
    return inner
 
 
@test_more
def test1():
 
    t1 = time.clock()
    g_ret = gen1(1000000)
    t2 = time.clock()
    init_t = t2 - t1
 
    t1 = time.clock()
    total = 0
    for v in g_ret:
        total += v
    t2 = time.clock()
    process_t = t2 - t1
 
    return init_t, process_t, total
 
 
@test_more
def test2():
 
    t1 = time.clock()
    g_ret = gen2(1000000)
    t2 = time.clock()
    init_t = t2 - t1
 
    t1 = time.clock()
    total = 0
    for v in g_ret:
        total += v
    t2 = time.clock()
    process_t = t2 - t1
 
    return init_t, process_t, total
 
 
if __name__ == "__main__":
    test1()
    test2()
cs

 

시험은 총 1000000개의 integer형 data를 취급하는 것으로 했으며 init, process time 및 해당 data를 모두 더한 값이 동일한지 살펴 보았습니다.

 

1. 최초 iterator를 얻어 오는 부분은 test1() 이 오래 걸립니다. 

※ test1에서 iterator를 가져오기 위해 전체 data를 memory에 올리므로 시간이 좀 더 걸립니다.

※ test2에서 generator iterator는 lazy evaluation을 하므로, 시간이 거의 소요되지 않습니다.

 

2. data를 for문을 통해 처리하는 부분은 test2가 더 오래 걸립니다.

※ generator iterator의 경우 lazy evaluation 을 하므로 over head가 있는 것 같습니다.

 

3. 결과적으로 init + process time을 고려하면 generator를 사용한 test2가 좀 더 빠른 모습을 보여줍니다.

 

반응형

'프로그래밍 > PYTHON' 카테고리의 다른 글

python - Equality, Identity  (0) 2021.02.12
python - Comprehension, Generator expression  (0) 2021.02.11
[환경설정] python - Linux anaconda  (0) 2021.02.10
python - Iterable, Iterator  (0) 2021.02.03
python - Decorator  (4) 2021.01.22