요새 파이썬 개발팀의 주요 이슈는 PEP-340 Anonymous Block 입니다. 거의 다른 이슈들을 완전히 누르고 하루에도 수십통씩 관련 메일이 올라올 정도로 다들 열에 올라 있는데, 이 논의와 비슷한 얘기는 이전에도 몇번 있긴 했지만 딱히 어디로 결론이 나지는 않았었습니다. (PEP-310, PEP-325) 그러나 4월 중순에 C++ 프로그래머였던 사람이 조심스럽게 질문을 한 것에 대한 답글들에서 개발자들이 열을 내기 시작해서, 귀도가 4월 27일에 직접 PEP를 쓰기에 이릅니다.
이번 PEP-340은 현재 드래프트 상태이고, 확실히 의견이 모아진 것도 아니며, 그냥 실험적으로 논의되는 상태를 정리하는 것을 위한 안이지만, 이전의 유사 주제의 PEP들에 비해 상당히 여러 분야를 한꺼번에 통합하고 있고, 신선한 개념을 많이 제공하고 있다는 점에서 뭔가 유사한 것이 약간의 부분이라도 파이썬 2.5에 들어갈 것 같은 감이 듭니다. 으흐흐~ 파이썬 2.5에는 특히 AST가 거의 들어갈 것이 확실시되고 있으니까.. 그 김에 문법도 확 -.-,;;
PEP-340에서 소개하는 Anonymous Block은 파이썬 1.5 이후의 문법 상의 가장 획기적인 변화라고 부를 수도 있겠는데, 사실 많은 수의 개발자들이 2.4까지 계속 문법 변화가 많았으니 이제 2.5부터는 문법은 바꾸지 말자하고 암묵적인 동의를 했음에도 불구하고, 이번에 예전에 수년동안 있었던 문법 변화보다 더 많은 변화가 들어가 버리니.. 파이썬 중도보수파들도 이제 파이썬의 변화에 반감을 느낄 것 같기도 합니다. 으흐~
Anonymous Block이 해결하려는 이슈를 소개해 드리자면, PEP에서 언급된 대로 “좋은 프로그래머들은 자주 나오는 코드를 재사용 가능한 함수로 분리”를 합니다. 그런데, 함수나 클래스로 쉽게 분리가 되는 경우도 많이 있지만, 어떤 경우에는 루틴의 앞부분과 끝부분, 오류처리부분과 루틴의 중간 중간이 드문드문 반복되는 패턴으로 자꾸 나오는 경우가 있습니다. 예를 들면, 공유 자원의 접근을 위한 뮤텍스라던지, DB 접근을 위한 트랜잭션 처리 블럭, HTML의 헤더/푸터나 table 앞뒤 장식, 임시 파일의 생성 등 수많은 경우가 해당이 될 수 있겠는데요. 이런 경우에는 콜백으로 빼서 클래스를 생성하자니 배보다 배꼽이 크게 되고, 그렇다고 매번 풀어쓰기에는 반복되는 로직을 자꾸 중복하게 되는 찝찝한 경우가 생기는데, 이런 경우를 극복하기 위해서 Anonymous Block (현재 파이썬 메일링에서는 그냥 “block”이라고 부르고 있습니다.)가 제안되었습니다.
즉, “block”에 진입하는 시점, 오류또는 정상 종료로 인한 이탈 시점, 반복을 하는 시점, 중간에 루프의 인자가 약간 바뀌는 시점 같은 것들을 기존의 문법인 제너레이터를 확장한 것과 짬뽕을 해서 멋지게 만들어 보자는 것이 요점입니다. 2.3부터 지원되고 있는 제너레이터는 이미 상당히 다양한 용도에 사용할 수 있는 성공한 문법이지만, next 메쏘드에 인자를 전달할 수가 없어서, 상태 관리가 매우 힘들다는 점이나 try: finally 블럭이나 try: except 블럭을 yield와 걸쳐서 사용할 수 없어서, 자원의 정상적인 해제가 불가능하다는 점에서 아쉬움이 있었는데 이러한 문제점도 여기서 완전히 해결되었습니다.
현재 상태에서 PEP-340에서 변경하는 기본 statement 변화는 이런 것들이 있습니다.
- __next__ 메쏘드 신설: 기존의 이터레이터 프로토콜에서는 __next__가 아니라 next메쏘드를 쓰고 있었는데, 이 이름이 범용으로는 아무래도 맞지가 않았기에, __next__로 새로운 메쏘드를 신설하고, __next__에 이제 인자 1개가 None이 기본값인 옵셔널 인자로 들어갑니다.
- __exit__ 메쏘드 신설: 이터레이터 프로토콜에 자원 해제를 위한 메쏘드가 없어서, 그동안 lock 해제 같은 것이 매우 곤란했었는데, 그 경우를 위해서 예외 발생 여부에 상관없이 항상 호출되는 __exit__ 메쏘드를 새로 만듭니다.
- next() 빌트인 함수: i.__next__()라고 맨날 쓰기에는 너무 보기가 안 좋아서, next(i)로 사용할 수 있도록 빌트인 함수가 신설됩니다.
- for 루프 변경: for 루프의 정의가 변경됩니다. 아래의 인자 있는 continue나 탈출 함수 호출을 위한 정의 변경이고, 예전 사용법으로 쓰는 경우는 똑같습니다.
- continue 인자 추가: continue 키워드 뒤에 이제 인자를 붙일 수 있게 되었습니다. continue 키워드 뒤에 인자를 쓰는 경우에는 바깥에서 돌고 있는 for또는 “block” 블럭의 이터레이터에게 전달됩니다. 즉, for 루프의 본문과 이터레이터가 직접 통신이 가능하게 되었습니다.
- Anonymous block 추가: 아직 이름이 정해지지 않은 (아직 “block”이라고 부르고 있습니다.) 새로운 블럭 키워드가 추가됩니다. 이 키워드는 for과 유사한 목적으로 사용될 수도 있지만, 이터레이터 인자를 항상 대상으로 하고 있다는 점에서 좀 다릅니다. 자세한 설명은 아래에서..
- 제너레이터 예외 처리: 이제 제너레이터의 yield statement가 try: except 블럭 안에도 들어갈 수 있게 되었으며, try: finally 블럭 안에도 들어갈 수 있습니다.
- yield statement 리턴값: 제너레이터의 __next__로 들어오는 인자를 받기 위해서 이제 yield statement가 들어온 값을 리턴합니다.
대충 훑어봐도 엄청난 변화임이 확실히 느껴지는데, 이게 아직 확실히 정해진 것은 아니니 허어억~ 하고 미리 놀라실 필요는 없습니다. (나중에 들어가면 그때 놀라면;; -o-) Anonymous Block을 사용하는 예제로 가장 많이 나오는 DB 트랜잭션 처리 같은 경우에는 이렇게 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def transaction(conn): cur = conn.cursor() # 이 부분은 제너레이터 생성시 실행 cur.execute('BEGIN WORK') try: yield cur # 최초 인자로 한번 넘겨 줌 exception: cur.execute('ROLLBACK') # 블럭 안에서 예외 발생 시 else: conn.commit() # 블럭 안에서 예외 발생 없이 종료 # 이 아래가 실제 실행 시작점 block transaction(conn) as txn: txn.execute('SQL~ SQL~~~') |
그리고, 이제 yield가 리턴값을 갖을 수 있기 때문에 유사-클로져나 유사-코루틴을 이제 쓸 수가 있게 되었습니다. 예를 들어서, 이런 코드가..
1 2 3 4 5 6 7 8 9 10 11 12 |
def accumulator(default=0): sum = default while True: sum += yield sum # 반복하면서 인자들을 모두 더함 block accumulator(0) as sum: # 현재 총합을 보여주고 새로 더할 값을 받음 v = input('%d >>> ' % sum) if v >= 0: continue v # 0 이상의 수가 들어오면 더하고 계속 else: break |
흐흐.. 결국 껍데기 부분의 루틴 분리에 획기적인 개선을 가져올 수 있는 좋은 도구가 될 수 있을 만한 것 같이 보입니다. 여전히 수많은 이슈들과 특히 키워드 이름을 무엇으로 할 것인가 등의 많은 문제들이 남아있지만, 아무래도 파이썬 2.5에 들어가면 가장 멋있을 것 같은 기능임에는 틀림이 없군요. 🙂 문법 변화라는 점에서는 원래 예정과는 좀 다르게 간다는 점에서는 약간 찝찝한 감이 있긴 하지만.. 뭐 이제 류창우님의 말씀 대로.. 파이썬도 C++이 가던 길을 걷고 있는 건지도.. (먼산)
Welcome to ruby!
루비의 블럭 구문을 들여오기 위한 대대적인 변경이군요. 😉