개요

  • 메모리 절약의 장점
  Project Euler 문제를 풀다보면 prime sieve를 해서 1 ~ n 미만인 소수에서 
  특정 연산을 수행하는 경우가 잦았습니다.
  1 ~ n 까지 loop를 돌면서 [2, 3, 5, 7, 11, 13 ....] 리스트로 저장한 후에 
  이를 다시 `for arr in arrays:` 와 같은 방식으로 또 loop를 돌려서 했더니
  코드도 지저분하고 loop도 2번 돌고 메모리에 들고 있어야 하니 메모리도 먹고
  10 ** 18 으로 커지면 메모리에 다 들고 있을 수도 없었습니다.
  
  그래서 찾아보니 generator가 있었고 메모리에 다 들고 있을 필요없고
  loop 돌면서 generator 함수를 호출하면 
  호출할 때마다 갱신된 겂을 yield로 반환해줘서 
  효과적으로 처리할 수 있었습니다.
  
  • 제너레이터 함수를 사용하면 iterator(반복자) 처럼 동작하는 함수를 선언할 수 있습니다.
  • Generator functions allow you to declare a function that behaves like an iterator, i.e. it can be used in a for loop.1

Iterator 2

  • An iterable object is an object that implements __iter__. __iter__ is expected to return an iterator object. 3
  • An iterator is an object that implements next.
    next is expected to return the next element of the iterable object that returned it,
    and raise a StopIteration exception when no more elements are available. 3
  • iteratornext를 수행하는 하나의 오브젝트입니다.
    next는 다음 elements를 리턴해주고, 다음 element가 없으면 StopIteration 처리합니다.

Dictionary Iterators

if k in dict: ...
# which is equivalent to

if dict.has_key(k): ...
# Dictionaries implement a tp_iter slot that returns an efficient iterator
# that iterates over the keys of the dictionary. 
# During such an iteration, # the dictionary should not be modified, 
# except that setting the value for an existing key is allowed 
# (deletions or additions are not, nor is the update() method). 
# This means that we can write

for k in dict: ...
# which is equivalent to, but much faster than

for k in dict.keys(): ...
# as long as the restriction on modifications to the dictionary (either by the loop or by another thread) are not violated.

# Add methods to dictionaries that return different kinds of iterators explicitly:

for key in dict.iterkeys(): ...

for value in dict.itervalues(): ...

for key, value in dict.iteritems(): ...

File iterators

Files implement a tp_iter slot that is equivalent to iter(f.readline, ""). This means that we can write

for line in file:
    ...
as a shorthand for

for line in iter(file.readline, ""):
    ...
which is equivalent to, but faster than

while 1:
    line = file.readline()
    if not line:
        break
    ...

yield 4

예제

  • 소수(Prime number) 생성하는 예를 보고나면 좀더 이해하기 쉽습니다. 5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def gen_primes(limit):
    D = {}
    q = 2
    while q <= limit:
        if q not in D:
            yield q  # 소수를 generate합니다. 
            D[q * q] = [q]
        else:
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]
        q += 1


print([i for i in gen_primes(100)])

# 실행결과
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
  • 코드 설명
    • 100 이하의 소수를 출력합니다.
    • 소수를 generate할 gen_primes()를 구현합니다.
    • 소수 조건에 맞으면 yield를 호출합니다.
    • for 루프를 돌때마다 새로운 값이 호출 되어 다음 값을 generate 합니다.

참조