PEP289: Generator Expressions

PEP [PEP]289 제너레이터 익스프레션은 2002년 1월에 처음 제안되어 얼마전에 파이썬 2.4에 채용하기로 결정된 문법입니다. 파이썬 2.0에서 도입된 리스트 컴프리헨션의 제너레이터 버전이라고 볼 수 있는데, 리스트 컴프리헨션이 전체 리스트를 일일이 다 만들어서 넘겨주기 때문에, 한꺼번에 실행되는터라 부하도 크고 메모리도 무진장 먹습니다. 요 문제를 해결하기 위해 제너레이터로 만들어주는 건데.. lambda와 list comprehension의 중간쯤 된다고 볼 수 있겠군요.. 흐흐.. 예를 들면, 리스트 컴프리헨션에서는 요렇게

sum([x*x for x in range(10000)]) 

10000개 원소의 리스트를 한꺼번에 다 계산해서 더하게 되는데, 제너레이터 익스프레션에서는

sum(x*x for x in range(10000)) 

이렇게 하면, 이게 제너레이터로 변신해서 sum함수에서 1개씩 이터레이션 할 때마다 실행되게 됩니다. 흐흐 만세~

그런데, 이 문법은 아무래도 모호성 문제가 있는데

a = (x for x in "abc")  # 요건 valid 
b = x for x in "abc"    # 요건 invalid (괄호가 없음)
f(x for x in "abc")     # 요건 valid. 예외적으로 함수 호출같이 괄호가 밖에 있으면 허용
f([x for x in "abc"])   # 요건 그냥 리스트 컴프리헨션..
c = [x for x in "abc"]  # 요것도 리스트 컴프리헨션..
d = [(x for x in "abc")] # 요건 제너레이터 익스프레션이 들어있는 리스트

이런식으로 뭐 결과적으로는 맞긴 한데.. 뭐 하여간 모호하긴 하군요.. 흐흐

자 그럼 제너레이터 익스프레션을 본격적으로 맛볼 시간!

# 시그마 x=0부터 9까지 x^2를 모두 더함 
print sum(x**2 for x in range(10))

# 0부터 99까지 3의 배수들의 평균값을 구함
print average(x for x in range(100) if x % 3 == 0)

# x, y가 각각 0과 10사이일 때 곱이 10의 배수인 것 중에 x+y가 가장 큰 쌍
print max((x+y, x, y) for x in range(11) for y in range(11) if x * y % 10 == 0)[1:]

하하 대단 -.,-;;

흐흐.. 그런데, 아직 PEP[PEP]289 는 구현이 안 나와있어서 시험해 볼 수는 없는데 Jeff Epler가 yield가 앞에 들어가는 옛날 형식 문법으로 구현한 compiler 패키지 기반으로 된 것만 나왔습니다. 그래서 진짜 파이썬에서 쓰는 parser 모듈로 구현을 한 번 해보려고 하고 있는데 문법이 야릇하다보니 문법 구현부터가 힘들군요 –; 일단 패치는 다음과 같이 만들어 봤는데.. arglist가 아무래도 test 토큰이 앞에 argument가 *로 붙은거랑 겹치다보니.. ambiguity가 자꾸 발생하는군요.. 이것 어떻게 해결해야할 지 –;;; -ㅇ-; BNF 잘 아시는 분께서는 좋은 의견이 있으시면 알려주세요~♡;;

83c83 
< atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}'
(앞줄에 이음) | '`' testlist1 '`' | NAME | NUMBER | STRING+
---
> atom: '(' [testgenexpr] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}'
(앞줄에 이음) | '`' testlist1 '`' | NAME | NUMBER | STRING+
92a93
> testgenexpr: test ( genexpr_for | (',' test)* [','] )
97c98
< arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
(앞줄에 이음) | '**' test)
---
> arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
(앞줄에 이음) | '**' test) | test genexpr_for
104a106,109
>
> genexpr_iter: genexpr_for | genexpr_if
> genexpr_for: 'for' exprlist 'in' test [genexpr_iter]
> genexpr_if: 'if' test [genexpr_iter]

8 thoughts on “PEP289: Generator Expressions”

  1. 예.. 사실은 제가 정한 캐릭터가 아니라, 학부 때 동아리 후배들이 딱 맞다고 알려줘서 쓰게 되었습니다 ^^;;;;

Comments are closed.