들어가기 전
- 이 글은 이펙티브 파이썬을 공부하며 작성한 글입니다
- 코드 : https://github.com/chickenchickenlove/effective-python/tree/master/item32
요약
- 리스트 컴프리헨션에서 입력이 크면 메모리 문제가 발생할 수 있음.
- 제네레이터 식은 한 번에 제네레이터가 반환되기 때문에 메모리를 효율적으로 사용할 수 있음.
- 제네레이터 식에 다른 제네레이터를 내포할 수 있음. 이를 통해 여러 제네레이터를 하나로 합성할 수 있음.
- 각 제네레이터는 상태를 가지기 때문에 이 부분을 유의해서 사용해야 함.
- 합성된 제네레이터 식은 매우 빠르게 실행되며 메모리도 효율적으로 사용함.
Item 32. 긴 리스트 컴프리헨션보다는 제네레이터 식을 사용하라.
# 리스트 컴프리헨션 사용 예시
# my_file.txt의 라인 수가 수십 조라면? → 메모리 터짐.
value = [len(x) for x in open('my_file.txt')]
print(value)
리스트 컴프리헨션의 문제점은 메모리 사용량과 관련이 있다. 리스트 컴프리헨션은 만들어 둔 객체를 모두 리스트에 보관하기 때문에 그만큼 많은 메모리를 사용한다. 만약 너무 많은 메모리를 사용하게 되면 프로그램이 종료될 수 있다.
위 코드에서 my_file.txt 파일이 수십 조의 라인으로 이루어져 있다고 가정해보자. 그러면 바로 메모리 부족으로 프로그램이 종료될 것이다.
# 제네레이터 식 사용해서 메모리 효율화
# 컴프리헨션에서 ()를 사용하면 제네레이터가 반환됨.
it = (len(x) for x in open('my_file.txt'))
print(it)
# next()로 다음 호출
next(it)
next(it)
# for문으로 다음 호출.
for v in it:
print(v)
가능하다면 제네레이터 식을 사용해서, 리스트 컴프리헨션과 비슷한 효과를 내면서 메모리를 효율적으로 사용해 볼 수 있다.
- 제네레이터 식의 결과로 제네레이터(이터레이터)가 반환됨.
- 이터레이터가 다음 인자로 넘어가려면 next()를 호출해야함.
it = (len(x) for x in open('my_file.txt'))
# 제네레이터 식 안에 제네레이터가 내포됨.
roots = ((x, x**0.5) for x in it)
print(it)
print(roots)
print(next(it))
print(next(it))
print(next(roots))
또한 리스트 컴프리헨션을 여러 번 내포할 수 있는 것처럼 제네레이터 식에도 제네레이터를 내포할 수 있다.
- roots 제네레이터에 next()를 호출하면, next(it)가 호출되면서 x를 획득하게 되고 (x, x**0.5)가 반환된다.
- 이터레이터는 상태를 가진다. 따라서 next(it)를 호출한 후에 next(roots)를 호출하게 되면, roots는 특정 값을 놓치게 된다.
- it에 대해서 전체 이터레이팅을 했을 때, [10, 9, 8, 7]을 받을 수 있다고 가정해보자.
- next(it) → next(roots)를 호출하게 되면, 10은 next(it)가 호출되었을 때 사용되었고, next(roots)에서는 9라는 값을 받게 된다.
'프로그래밍 언어 > 파이썬' 카테고리의 다른 글
Effective Python Item 34. send로 제네레이터에 데이터를 주입하지 마라. (0) | 2024.01.21 |
---|---|
Effective Python Item 33. yield from을 사용해 여러 제네레이터를 합성하라. (0) | 2024.01.20 |
Effective Python Item 30. 리스트를 반환하기보다는 제너레이터를 사용하라 (0) | 2024.01.15 |
Effective Python Item 29. 대입식을 사용해 컴프리헨션 안에서 반복작업을 피해라. (0) | 2024.01.14 |
Effective Python Item 16. 딕셔너리 Key에 대한 접근은 get을 사용하라. (0) | 2024.01.14 |