핀아의 저장소 ( •̀ ω •́ )✧

generator(제너레이터) 본문

Computer Science/Python

generator(제너레이터)

_핀아_ 2023. 5. 17. 17:44

generator 는 간단하게 설명하면 iterator 를 생성해 주는 function이다. iterator 는 next() 메소드를 이용해 데이터에 순차적으로 접근이 가능한 object 이다.

💡 이터레이터란 next() 함수 호출 시 계속 그다음 값을 반환하는 객체

generator 는 일반적인 함수와 비슷하게 보이지만, 가장 큰 차이 점은 yield 라는 구문일 것이다. 아래는 generator 함수의 예시 구문이다.

def generator(n):

    i = 0

    while i < n:

        yield i

        i += 1

일반 함수와의 차이는 yield 외에는 없다. 그렇다면 먼저 yield 구문이 무엇인지 먼저 알아보자.

✅ yield

yield 는 generator 가 일반 함수와 구분되는 가장 핵심적인 부분이다. yield 를 사용함으로서 어떤 차이가 있게 되는지 살펴보자.

먼저, 일반적인 함수의 경우를 생각해보자.

일반적인 함수는 사용이 종료되면 결과값을 호출부로 반환 후 함수 자체를 종료시킨 후 메모리 상에서 클리어 된다.

하지만, yield 를 사용할 경우는 다르다.

generator 함수가 실행 중 yield 를 만날 경우, 해당 함수는 그 상태로 정지 되며, 반환 값을 next() 를 호출한 쪽으로 전달 하게 된다. 이후 해당 함수는 일반적인 경우 처럼 종료되는 것이 아니라 그 상태로 유지되게 된다. 즉, 함수에서 사용된 local 변수나 instruction pointer 등과 같은 함수 내부에서 사용된 데이터들이 메모리에 그대로 유지되는 것이다.

 

아래 예시를 보자.

def generator(n):

    i = 0

    while i < n:

        yield i

        i += 1



for x in generator(5):

print x


0

1

2

3

4

위 구문을 하나하나 살펴보자.

  1. for 문이 실행되며, 먼저 generator 함수가 호출된다.
  2. generator 함수는 일반 함수와 동일한 절차로 실행된다.
  3. 실행 중 while 문 안에서 yield 를 만나게 된다. 그러면 return 과 비슷하게 함수를 호출했던 구문으로 반환하게 된다. 여기서는 첫번재 i 값인 0 을 반환하게 된다. 하지만 반환 하였다고 generator 함수가 종료되는 것이 아니라 그대로 유지한 상태이다.
  4. x 값에는 yield 에서 전달 된 0 값이 저장된 후 print 된다. 그 후 for 문에 의해 다시 generator 함수가 호출된다.
  5. 이때는 generator 함수가 처음부터 시작되는게 아니라 yield 이후 구문부터 시작되게 된다. 따라서 i += 1 구문이 실행되고 i 값은 1로 증가한다.
  6. 아직 while 문 내부이기 때문에 yield 구문을 만나 i 값인 1이 전달 된다.
  7. x 값은 1을 전달 받고 print 된다. (이후 반복)

✅ generator expression

위와 같은 generator 함수를 좀 더 쉽게 사용할 수 있도록 generator expression 을 제공한다.

list comprehension 과 비슷하지만, [ ] 대신 ( ) 를 사용하면 된다.

 

아래는 0 ~ 9 사이 정수 중 홀수 를 list 와 generator object 로 생성한 예제이다.

>>> [ i for i in range(0, 10) if i % 2 ]

[1, 3, 5, 7, 9]

>>> ( i for i in range(0, 10) if i % 2 )

<generator object <genexpr> at 0x7f6105d90960>

( ) 를 사용하면 위와 같이 generator object 로 생성됨을 볼 수 있다.

 generator를 왜 사용하는가

  1. memory를 효율적으로 사용할 수 있다.
    • list 의 경우 사이즈가 커질 수록 그만큼 메모리 사용량이 늘어나게 된다. 하지만, generator 의 경우는 사이즈가 커진다 해도 차지하는 메모리 사이즈는 동일하다. 이는 list 와 generator의 동작 방식의 차이에 기인한다.
    • list 는 list 안에 속한 모든 데이터를 메모리에 적재하기 때문에 list의 크기 만큼 차지하는 메모리 사이즈가 늘어나게 된다. 하지만 generator 의 경우 데이터 값을 한꺼번에 메모리에 적재 하는 것이 아니라 next() 메소드를 통해 차례로 값에 접근할 때마다 메모리에 적재하는 방식이다.
    • 따라서 list 의 규모가 큰 값을 다룰 수록 generator의 효율성은 더욱 높아지게 된다.
  2. Lazy evaluation 즉 계산 결과 값이 필요할 때까지 계산을 늦추는 효과를 볼 수 있다.
def sleep_func(x):

print "sleep..."

time.sleep(1)

return x

위 sleep_func() 함수는 1초간 sleep 을 수행한 후 x 값을 return 하는 함수이다.

만약 위 sleep_func() 함수를 이용해 llist 와 generator 를 생성하면 어떻게 동작할까.

# list 생성

list = [sleep_func(x) for x in range(0, 5)]



for i in list:

print i


<결과>

sleep...

sleep...

sleep...

sleep...

sleep...

0

1

2

3

4
# generator 생성

gen = (sleep_func(x) for x in range(0, 5))

for i in gen:

print i


<결과>

sleep...

0

sleep...

1

sleep...

2

sleep...

3

sleep...

4

위 결과 값을 보면, generator 를 사용하였을 경우 어떤 차이가 있는지 알 수 있다. list의 경우 list comprehension을 수행 할 때, list의 모든 값을 먼저 수행하기 때문에 sleep_func() 함수를 range() 값 만큼 한번에 수행하게 된다. 만약 sleep_func() 에서 수행하는 시간이 길거나 list 값이 매우 큰 경우 처음 수행 할때 그만큼 부담으로 작용된다.

하지만 generator 의 경우 generator 를 생성할 때는 실제 값을 로딩하지 않고, for 문이 수행 될때 하나씩 sleep_func()을 수행하며 값을 불러오게 된다. 수행 시간이 긴 연산을 필요한 순간까지 늦출 수 있다는 점이 특징이다.


🎃 참고

https://bluese05.tistory.com/56

 

python generator(제너레이터) 란 무엇인가

Python Generator 먼저 python docs 의 generator 에 대한 정의를 보자. generator A function which returns an iterator. It looks like a normal function except that it contains yield statements for producing a series of values usable in a for-loop or

bluese05.tistory.com

https://wikidocs.net/134909

'Computer Science > Python' 카테고리의 다른 글

클래스와 모듈  (0) 2023.05.16
Comments