반응형
SMALL
제너레이터 설명
제너레이터란 무엇인가? 그리고 왜 사용해야하는가?
제너레이터란 iterator를 생성해주는 함수이다. 즉, 반복문을 활용하여 데이터를 순회하면서 처리하는 것을 의미한다.
이해하기 추상적인것 같아서 다음의 코드로 확인해보자.
iterator
우리는 리스트, 문자열 등을 만든 후 해당 리스트에 있는 객체를 순환하며 하나씩 꺼내서 사용할 수 있다. 이러한 과정을 순환(Iteration)이라고 한다.
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
위와 같이 순환이 가능한 것들은 우리가 원하는 만큼 접근해서 즉시 사용할 수 있다는 장점도 있지만, 단점으로는 모든 값을 메모리에 담고 있어야 하기 때문에 큰값을 처리할때는 좋지 못하다.
이러한 단점을 해결하기 위해서 만들어진게 Iterator이다.
다음은 제너레이터를 활용한 코드와 메모리 사용량에 대해서 알아본다.
# 실행 중 while 문 안에서 yield를 만나게 된다.
# 그러면 return 과 비슷하게 함수를 호출했던 구문으로 반환하게 된다.
# 여기서는 첫번째 i 값인 0을 반환한다.
# 하지만 반환했다고 generator 함수가 종료되는 것이 아니라 그대로 유지한 상태이다.
def generator(n):
i = 0
while i < n:
yield i # 제너레이터가 일반 함수와 구분되는 가장 핵심!!!
i += 1
# for 문이 실행되며 generator 함수가 호출된다.
# generator 함수는 일반 함수와 동일한 절차로 실행된다.
for x in generator(5):
# x 값에는 yield에서 전달된 0 값이 저장된 후 출력된다.
# 그 후 for 문에 의해 다시 generator 함수가 호출된다.
# 이 때, generator 함수는 처음부터 시작되는 것이 아니라 yield 이후부터 시작된다.
# 따라서 "i += 1" 문장이 실행되고 i 값은 1로 증가한다.
print(x)
# 출력
0
1
2
3
4
- 일반적인 함수의 경우, 사용이 종료되면 결과 값을 호출부로 반환한 뒤 함수 자체를 종료시킨 후 메모리 상에서 정리(clear)된다.
- 하지만, yield는 다르다. generator 함수가 실행 중에 yield를 만날 경우, 해당 함수는 그 상태로 정지되며, 반환 값을 next()를 호출한 쪽으로 전달한다. 이후 해당 함수는 일반적인 경우처럼 종료되는 것이 아니라 그 상태로 유지되게 된다. 즉, 함수에서 사용된 로컬 변수나 instruction pointer 등과 같은 함수 내부에서 사용된 데이터들이 메모리에 그대로 유지된다.
Generator Expression
- Generator Expression: generator 함수를 더 쉽게 사용하기 위해 제공되는 것
# 0 ~ 9 사이 정수 중 홀수를 list와 generator object로 생성
>>> [i for i in range(10) if i % 2]
[1, 3, 5, 7, 9]
>>> (i for i in range(10) if i % 2)
<generator object <genexpr> at 0x7f6105d90960>
()를 사용하면 위와 같이 generator object로 생성된다.
Generator 사용 이유
- 메모리를 효율적으로 사용할 수 있다.
>>> import sys
# list
>>> sys.getsizeof( [i for i in range(100) if i % 2] )
536
>>> sys.getsizeof( [i for i in range(1000) if i % 2] )
4280
# generator
>>> sys.getsizeof( (i for i in range(100) if i % 2) )
80
>>> sys.getsizeof( (i for i in range(1000) if i % 2) )
80
list의 경우 사이즈가 커질수록 메모리 사용량이 늘어남. 반면 generator의 경우 사이즈가 커져도 차지하는 메모리 사이즈는 동일함
- 추가 설명
- list는 list 안에 속한 모든 데이터를 메모리에 적재하기 때문에 list의 크기만큼 차지하는 메모리 사이즈가 늘어나게 된다. 반면 generator는 데이터 값을 한꺼번에 메모리에 적재하는 것이 아니라 next() 메서드를 통해 차례로 값에 접근할 때마다 메모리에 적재한다. 따라서 list의 규모가 큰 값을 다룰수록 generator의 효율성은 높아진다.
반응형
LIST
'프로그래밍 > Python' 카테고리의 다른 글
[TDD][Python] unittest - 예제로 익혀보기(3) (0) | 2022.03.16 |
---|---|
[TDD][Python] unittest - 예제로 익혀보기(2) (0) | 2022.03.16 |
[TDD][Python] unittest - 예제로 익혀보기(1) (0) | 2022.03.16 |
[TDD][Python] 단위 테스팅이란 (0) | 2022.03.16 |
[Python] Python Image Crawling+Ubuntu18.04 ::우주를놀라게하자 (0) | 2019.08.14 |