2011년 7월 30일 토요일

파이썬 코루틴 (python coroutine) -2

코루틴의 예제, 일단 아래 예제를 보세요
출처는 http://www.dabeaz.com/coroutines/ 입니다.

def coroutine(func):
    
    def start(*args, **kwargs):
        cr = func(*args, **kwargs)
        cr.next()
        return cr
    
    return start


# Example use
if __name__ == '__main__':
    @coroutine
    def grep(pattern):
        print "Looking for %s" % pattern
        while True:
            line = (yield)
            if pattern in line:
                print line,

    g = grep("python")
    # Notice how you don't need a next() call here
    g.send("Yeah, but no, but yeah, but no")
    g.send("A series of tubes")
    g.send("python generators rock!")
        

코루틴을 데코레이터로 선언을 합니다.

이 데코레이터 함수의 역할은 코루틴을 선언할 경우 자동으로 next()를 호출해주는 역할을 합니다.

코루틴의 경우 genertor로 선언을 하고, next()를 호출호출해주어야 준비상태로 들어갑니다.
next()를 호출하는게 필수적이긴 하나 번거로운 일이기 때문에 데코레이터를 써서 처리를 한것이죠

그리고 또 중요한 부분은 ,
yield를 문을 보시면, 뒤에 변수가 없습니다.  이것은 yield를 입력으로 받겠다는 소리입니다.
yield에 변수가 있으면 이것을 출력으로 내보내는데, 위에 구문을 보시면,
yield는 입력으로 받아서 line으로 저장을 하는 것입니다.

g = grep("python")
g.next()
원래는 이랬던 코드가 데코레이터를 사용함으로써
g = grep("python")
이렇게 되었고요,

제네레이터에서 출력을 담당하던 yield 구문이 코루틴에서는 입력을 담당하게 됩니다,

그래서 제네레이터를 producer , 코루틴을 consumer라고 표현을 하는것이죠.

파이썬 제네레이터 (python generator) - next()

이번글은 제네레이터에 대해서 좀 써보겠습니다.



일단 제네레이터는 함수형태로 선언이 되어있어야며,

함수한에 yield 구문이 있어야 generator로 선언이 됩니다.

제네레이터와 이터레이터는 유사하면서도 약간의 차이가 있는데 다음예제를 보시죠..

def countdown(n):
  print 'counting down from %d' % n 
  while n > 0:
     yield n 
     n -= 1
  return 

>>> c = countdown(10)
>>>

>>> c.next() 
Counting down from 10
10
>>> c.next()
9


일단 c로 generator가 생성이 되었습니다.
기본적으로 generator는 next() 를 호출하면 다음 yield가 있는데까지 동작을 하고,
현재 status를 keep 합니다.

그래서 처음 c.next()를 실행시면, 메시지랑 10을 출력하고 멈춥니다.

그리고 다음 c.next()를 호출하면 9를 출력하고 멈춥니다.

언제까지 동작을 하냐 하면, 더이상 yield 구문이 나오지 않을때 ,

그때 raise StopIteration 을 발생시키며, 제네레이터가 멈춥니다.

이것이 제네레이터의 기본적인 동작입니다.

이걸 list처럼 갖다가 쓰면, 똑같이 동작을 합니다.

위에서 선언한 countdown을 그냥 쓰면 다음과 같습니다.
for i in countdown(10):
   print i, 

10 9 8 7 6 5 4 3 2 1 0 

파이썬 데코레이터 (python decorator)

- 파이썬 데코레이터

데코레이터는 한글 이름은 장식자 정도로 번역되는데
이 역시 design pattern에서 나온 이름이고요,

근데 이게 장식자라고 하면 일단 뭔가 감도 잘 안오고 하는데

이 데코레이터의 개념은 일종의 함수 wrapping입니다.

함수를 바깥에서 한번 싸는거죠.




@deco_method
def func1(x):
    return x+1

이런식의 함수가

func1 = deco_method(func1)  

이런식으로 한번 래핑(wrapping)을 해주는 것입니다.


import time

def elapsed_time(functor):
     def decorated(*args, **kwargs):
             start = time.time()
             functor(args, kwargs)
             end = time.time()
             print "Elapsed time: %f" % (end-start)
     return decorated
  

@elapsed_time
def hello():
     print 'hello'
    
보통 이런식으로 많이들 사용합니다. 위의 예제는 하나의 함수가 시간이 얼마나 걸리는지를 재는데 사용하는 예제이고요,

functor가 래핑할 함수이고요,
start, end부분은 전후로 들어갈 부분입니다.

그래서 사용예제들을 보면 디버깅하는데 사용하거나,
-> arg, kwargs를 조사해서, 값을 찍어주는 용도로 쓰기도 하고요

자주사용하는 진입루틴, 출구루틴에 사용을 합니다.

ex ) @login
login이 되어있으면 함수를 실행 아니면, 패스하는 식의 조건을 걸고,
함수를 실행시키는 다던지 하는 용도로 많이 사용을 합니다.


또 데코레이터는 argument를 받을 수도 있습니다.

@deco_method(argument)

이런형태로 쓰여져서 실제로 함수를 wrapping하는 중간에
다른동작도 가능하게 설계가 되어있습니다.



찾아보면 활용법이 많은 방법입니다.
전통적인 언어와는 좀 다르기때문에 헷갈릴수도 있는데 쓰면 쓸수록 장점이 많은 방법입니다.

또 위에서는 함수 데코레이터에 대해서만 얘기를 했는데,
클래스 데코레이터라는게 있습니다.

요것에 대해서는 조만간 또 작성을 해보겠습니다.














파이썬의 중요한 개념 (sequence) - 수열

파이썬에서 가장 중요한 개념이 뭐냐고 물어본다면

저는 이렇게 대답하겠습니다. 집합(set)과 수열(sequence)라고

그이유는 다음과 같습니다. 괜히 중학교, 고등학교 1학년 첫번재 단원이 집합이 있는게 아닙니다.

현대 수학에서 가장 중요한 개념중의 하나가 집합이라는 거죠,

그리고 sequence야 말로, 파이썬의 존재 이유라고 할수 있습니다.

수많은 computer science 연구자이 하려고 했던것은

어떻게 하면 수학을 컴퓨터의 영역으로 끌고 올것인가의 문제였습니다

그래서 C에서 Linked list 부터 시작을 해서 , STL (standard template libarary)
그리고 현대적, C#에 이르기까지 많은 데이터 구조들이
결국엔 수학기호/표현들을 어떻게 구현할까 하는 문제였습니다

수학을 기계적으로 표현할 수 있는가? 에 대해서

최소한 discreate mathmatics에 관해서는 파이썬이 그 하나의 답이 아닐까 봅니다.

파이썬 코루틴 (python coroutine) -1

파이썬과 코루틴

이 개념을 이해하는데 상당히 힘들었습니다. 익숙하지 않은 내용들이 많고,
또 이 개념을 설명해 주는 자료가 그리 많지 않네요

파이썬 2.5부터 지원하는 내용인것 같습니다.

일단 가장 잘 설명해 놓은 자료는 이것 입니다. .

다베아즈 아즈씨의 설명, http://www.dabeaz.com/coroutines/index.html

일단 코루틴은 Lua에서 주로 많이 사용하는 개념으로 보입니다.

여기서 나오는 개념들은 yield, generator, iterator들인데,

이게 다른 언어에서 좀 생소한 개념들이라 좀 헷갈렸습니다.

일단 generator는 producer라고 합니다.
데이터를 생산해 내는 역할을 하죠

이에 반하여 coroutine은 consumer입니다.
데이터를 받아 먹는 역할을 합니다.

여기서 중요한 역할을 하는 구문이 yield입니다.

yield가 2.5 이전 버젼에서는 오직 generator의 구문으로만 쓰였습니다.

이전의 예를 들었던 아래의 구문에서는
def iter_func:
  i =1
  while True:
    yield i 
    i += 1

m  = iter_func()
print m.next()
print m.next()

>> ---------------------
1 
2


yield는 generator구문을 잠시 세우는 역할을 합니다.

위의 구문에서는 일단 generator가 선언된 다음에

next() 를 호출하면, yield가 써진 구문에서 멈추죠.

그리고 다음 next()을 호출하면 다음 yield가 보일때까지 돌다가 멈춥니다.

코루틴도 마찬가지인데
좀 다른것은 제네레이터에서 yield는 마치 return을 대신해서 사용하는 것 처럼 보입니다

코루틴은 이 yield를 입력으로 사용합니다.

자세한 내용은 coroutine -2 에서 이어가도록 하겠습니다.