Python의 Generator와 yield 키워드

Python의 반복문

보통 for 구문을 사용해서 0부터 99까지 반복한다고 하면 다른 프로그래밍 언어에선 이런 느낌이 됩니다.

for (let i = 0; i < 99; ++i) {
  do_something(i);
}

하지만 Python에선 for문이 저런 구조가 아닙니다. 그렇기에 우리는 range를 쓴다고 알고 있습니다.

for i in range(100):
    do_something(i)

그럼, range는 뭘까요? range(100)을 실행하면 어떻게 되길래 우리가 원하는 반복문이 되버리는 걸까요? 일단 Python 2에서 확인해보도록 합시다.

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(range(10))
<type 'list'>
>>> for i in range(10):
...   print i**3
...
0
1
8
27
64
125
216
343
512
729

100은 블로그에 담기엔 예시결과로는 너무 큰 관계로 10으로 줄였습니다. 실행하면 list로 0 이상 10 미만의 숫자가 들어가는 것을 확인할 수 있습니다. 도움말을 읽으면 당연히 알 수 있지만, range 함수는 정해진 범위를 list로 만들어줍니다. for문은 range의 결과로 나온 list에서 1개씩 뽑아서 사용하는 것이구요. Python의 for는 다른 언어에서의 foreach라고 부르는 것들과 비슷합니다.

for (let i of myArray) {
  do_something(i);
}

Python의 이런 반복은 얼핏보면 편하지만 함정이 있습니다. 만약 0부터 1000억까지 반복을 해야한다면 어떨까요? range(100000000)이라고 적으면 0부터 1000억-1 만큼의 인자가 들어있는 list가 생겨날 것입니다. list에 들어있는 것도 결국 컴퓨터가 저장하고 있어야 하는데 이대로 가다간 메모리가 버틸까요? 이 방법으로 접근하면 너무나도 비효율적입니다. Python으론 이런 방법밖에 없는걸까요?

이 문제를 해결하기 위해 Python 2에는 xrange라는 함수가 있습니다. Python 3에서는 기존의 range를 xrange가 대체했습니다. 위의 예제들을 xrange로 바꿔서 다시 해보죠.

>>> xrange(10)
xrange(10)
>>> type(xrange(10))
<type 'xrange'>
>>> for i in xrange(10):
...   print i**3
...
0
1
8
27
64
125
216
343
512
729

일단 반복문이 잘 돌아간다는 것은 알 수 있지만 그 외의 값은 미궁속입니다.

Python 2의 xrange / Python 3 range 동작 살펴보기

일단 xrange가 어떻게 for문에 값을 전달하는지 알아봅시다. 먼저 xrange 값을 하나 만듭니다. 그리고 iter함수로 iterator를 받습니다.

>>> ten = xrange(10)
>>> it = iter(ten)
>>> it
<rangeiterator object at 0x10f27bde0>

그러면 이제 받은 값으로 ten의 구성요소에 하나씩 접속해볼 수 있습니다.

>>> next(it)
0
>>> next(it)
1
>>> next(it)
2

그리고 next 함수를 이용해서 값을 원하는 시점에 하나씩 받아올 수 있습니다. for문은 이 방식을 이용해서 xrange값의 iterator를 받고 내부적으로 next를 호출해서 사용합니다.

이것은 Python 3의 range도 동일합니다.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

>>> ten = range(10)
>>> ten
range(0, 10)
>>> it = iter(ten)
>>> it
<range_iterator object at 0x106c70ed0>
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2

Generator

하지만 이건 Python에서 기본 지원하는 경우이고, 만약 수없이 많은 자료를 돌아다니면서 반복문을 돌려야한다면 어떨까요? 가령 수백만줄의 파일을 읽어서 한줄씩 처리중이었다면 어떻게 해야할까요? 모두 list에 올려놓고 하기엔 메모리가 버티지 못할 것입니다. 그 경우를 위해 Generator가 있습니다.

가볍게 0에서 9까지의 세제곱을 출력하는 Generator를 만들어서 사용해봅시다.

def gen():
    for i in range(10):
        yield i ** 3

for x in gen():
    print(x)

여기서 gen 함수가 바로 generator입니다.

>>> gen()
<generator object gen at 0x106aec1a8>

yield

Generator에서는 yield라는 키워드를 사용합니다. yield의 동작을 알아봅시다.

def gen():
    yield 'one'
    yield 'two'
    yield 'three'

g = gen()
print(next(g))  # one
print(next(g))  # two
print(next(g))  # three
print(next(g))  # raise StopIteration

yield는 함수 실행 중간에 빠져나올 수 있는 generator를 만들 때 사용합니다. return이었다면 'one'이 반환되고 끝났겠지만 실제로는 그 뒤로도 다시 사용할 수 있었죠.

yield는 단순히 값을 내보낼 수만 있는 것은 아니고, 넣어줄 수도 있습니다.

def gen():
    val = 111111
    while True:
        val = (yield val) * 111111

g = gen()
print(next(g))  # 111111
print(g.send(2))  # 222222
print(g.send(3))  # 333333

뭐에 쓰지?

위에서도 언급했지만 대용량 자료 처리등은 메모리에 모두 올려놓고 할 수 없습니다. 그런 경우 한 줄씩 읽은 뒤 generator를 이용한 반복처리를 하면 편합니다. 실제로도 Flask에서의 대용량 파일 전송, Sphinx의 확장 개발등에 사용됩니다.

요약

  1. yield 키워드를 사용하면 generator를 만들 수 있다.
  2. generator는 한번에 끝나지 않고 여러번에 걸쳐 입출력을 받을 수 있다.
  3. 대용량 처리 함수 제작 등에 편리하다
  4. 따라서, list가 필요한게 아니라면 Python 2에서 반복은 xrange를 쓰자.

[출처] https://item4.github.io/2016-05-09/Generator-and-Yield-Keyword-in-Python/

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
137 How to automatically search and download torrents with Python and Scrapy 졸리운_곰 2017.02.26 774
136 Web scraping, article extraction and sentiment analysis with Scrapy, Goose and TextBlob 졸리운_곰 2017.02.26 395
135 Windows 64 bit 에서 Python 단일 EXE 파일 만들기 file 졸리운_곰 2017.02.26 975
134 [Python] 네이버 주식 종목별 일별 데이터 가져오기 file 졸리운_곰 2017.02.24 1869
133 [파이썬으로 웹 크롤러 만들기] 크롤링 시작하기(3/3) file 졸리운_곰 2017.02.16 705
132 [파이썬으로 웹 크롤러 만들기] 크롤링 시작하기(2/3) file 졸리운_곰 2017.02.16 709
131 [파이썬으로 웹 크롤러 만들기] 크롤링 시작하기(1/3) file 졸리운_곰 2017.02.16 772
» Python의 Generator와 yield 키워드 졸리운_곰 2017.02.16 415
129 Python으로 RESTAPI 이용하기 졸리운_곰 2017.02.11 462
128 Learning Django and AngularJS 졸리운_곰 2017.02.06 1694
127 Application Skeleton for Flask and AngularJS file 졸리운_곰 2017.02.06 596
126 Flask by Example - Integrating Flask and Angular file 졸리운_곰 2017.02.06 1002
125 KAIST의 Flask 세미나 자료 whitegold-20130515-1.pdf file 졸리운_곰 2017.02.01 850
124 Flask로 만들어 보는 WSGI 어플리케이션 file 졸리운_곰 2017.02.01 529
123 [Flask, python], 빠르게 시작하기 file 졸리운_곰 2017.01.29 1493
122 [Django 17] Django 디버깅 file 졸리운_곰 2017.01.28 1185
121 [Django 16] Django - Site Deployment 졸리운_곰 2017.01.28 598
120 [Django 15] 샘플 - Feedback 예제 file 졸리운_곰 2017.01.28 474
119 [Django 14] Static 파일 file 졸리운_곰 2017.01.28 794
118 [Django 13] Django 폼 (Form) 졸리운_곰 2017.01.28 347
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED