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:] |
하하 대단 -.,-;;
흐흐.. 그런데, 아직 PEP289 는 구현이 안 나와있어서 시험해 볼 수는 없는데 Jeff Epler가 yield가 앞에 들어가는 옛날 형식 문법으로 구현한 compiler 패키지 기반으로 된 것만 나왔습니다. 그래서 진짜 파이썬에서 쓰는 parser 모듈로 구현을 한 번 해보려고 하고 있는데 문법이 야릇하다보니 문법 구현부터가 힘들군요 –; 일단 패치는 다음과 같이 만들어 봤는데.. arglist가 아무래도 test 토큰이 앞에 argument가 *로 붙은거랑 겹치다보니.. ambiguity가 자꾸 발생하는군요.. 이것 어떻게 해결해야할 지 –;;; -ㅇ-; BNF 잘 아시는 분께서는 좋은 의견이 있으시면 알려주세요~♡;;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
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] |