[Python] Skill of coding - comprehension이 클 때는 generator

Hyeseong·2020년 12월 9일
0

python skill of coding

목록 보기
2/18

comprehension이 클 때는 제너레이터 표현식을 고려하자

리스트 컴프리헨션의 문제점은 입력 시퀀스에 각 값별로 아이템을 하나씩 담은 새 리스트를 통째로 생성한다는 점이다.
입력이 적을 떄는 괜찮지만 클 떄는 메모리를 많이 소모해서 프로그램을 망가뜨리는 원인이 되기도 한다.

예를 들어 파일을 읽고 각 줄에 있는 문자의 개수를 반환한다고 하자. 이 작업을 리스트 컴프리헨션으로 하면 파일에 있는 각 줄의 길이만큼 메모리가 필요하다. 파일에 오류가 있거나 끊김이 없는 네트워크 소켓일 경우 리스트 컴프리헨션을 사용하면 문제가 발생한다. 다음은 입력값이 적은 경우만 처리할 수 있는 방식으로 리스트 컴프리헨션을 사용한 예다.

이 문제를 해결하기 위해 리스트 컴프리헨션과 제너레이터를 일반화한 제너레이터 표현식을 제공한다. 제너레이터 표현식은 실행될 떄 출력 시퀀스를 모두 구체화(여기서는 메로리에 로딩)하지 않는다. 대신에 표현식에서 한 번에 한 아이템을 내주는 이터레이터로 평가된다.

제너레이터 표현식은 () 문자 사이에 리스트 컴프리헨션과 비슷한 문법을 사용하여 생성한다. 다음은 이전 코드와 동일한 기능을 제너레이터 표현식으로 작성한 예다. 하지만 제너레이터 표현식은 즉시 이터레이터로 평가되므로 더는 진행 되지 않는다.

import random
with open('my_file.txt', 'w') as f:
    for _ in range(10):
        f.write('a' * random.randint(0, 100))
        f.write('\n')

value = [len(x) for x in open('my_file.txt')]
print(value)
[68, 59, 81, 96, 67, 75, 8, 89, 69, 47]
it = (len(x) for x in open('my_file.txt'))
print(it)
print(next(it))
print(next(it))
<generator object <genexpr> at 0x0000028311BF7F90>
68
59

필요할 떄 제너레이터 표현식에서 다음 출력을 생성하려면 내장 함수 next로 반환 받은 이터레이터를 한 번에 전진시키면 된다 코드에서는 메모리 사용량을 걱정하지 않고 제너레이터 표현식을 사용하면 된다.

또 다른 장점은 다른 제너레이터 표현식과 함께 사용한다는 점!
앞의 제너레이터 표현식이 반환한 이터레이터를 다른 제너레이터 표현식의 입력으로 사용한 예다.

roots = ((x, x**0.5) for x in it)

이 이터레이터를 전진시킬 떄마다 루프의 도미노 효과로 내부 이터레이터도 전진시키고 조건 표현식을 계산해서 입력과 출력을 처리한다.

print(next(roots))
(81, 9.0)

이렇게 제너레이터를 연결하면 파이썬에 매우 빠르게 실행 할 수 있어요 큰 입력 스트림에 동작하는 기능을 결합하는 방법을 찾을 때는 제너레이터 표현식이 최선의 도구에요. 단, 제너레이터 표현식이 반환한 이터레이터에는 상태가 있으므로 이터레이터를 한 번 넘게 사용하지 않도록 주의해야합니다.

핵심 정리

  • 리스트 컴프리헨션은 큰 입력을 처리할 때 너무 많은 메모리를 소모하여 문제를 일으킬 수 있음
  • 제너레이터 표현식은 이터레이터로 한 번에 한 출력만 만드므로 메모리 문제를 피할 수 있다.
  • 한 제너레이터 표현식에서 나온 이터레이터를 또 다른 제너레이터 for서브 표현식으로 넘기는 방식으로 제너레이터 표현식을 조합할 수 있다.
  • 제너레이터 표현식은 서로 연결되어 있을 때 매우 빠르게 실행된다.
profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글