ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 제너레이터(발생자)
    Python 2023. 10. 24. 15:39

    제너레이터는 이터레이터를 만들어 주는 함수

    이터레이터는 __iter__, __next__ 또는 __getitem__ 메서드를 구현해야 하지만 제너레이터는 함수 안에서 yield 키워드만 사용하면 끝

    > 이터레이터보다 훨씬 간단하게 작성 가능

    # yield 값
    
    def number_generator():
        yield 0
        yield 1
        yield 2
    
    for i in number_generator():
        print(i)
        
    # 실행 결과
    0
    1
    2

     

    제너레이터 객체가 이터레이터인지 확인

    g = number_generator()
    print(g)
    print(dir(g))
    
    # 실행 결과
    <generator object number_generator at 0x00000149F9478B40>
    
    ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
    '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__',
    '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__',
    '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
    '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running',
    'gi_suspended', 'gi_yieldfrom', 'send', 'throw']

    __iter__, __next__ 메서드가 들어 있음

    실제로 __next__ 호출해 보면 숫자 0, 1, 2가 나오다가 StopIteration 예외 발생

    0
    1
    2
    Traceback (most recent call last):
      File "c:\Users\user\Desktop\generator.py", line 19, in <module>
        print(g.__next__())
              ^^^^^^^^^^^^
    StopIteration

    이터레이터는 __next__ 메서드 안에서 직접 return으로 값을 반환, 제너레이터는 yield에 지정한 값이 __next__ 메서드(next 함수)의 반환값으로 나옴

    제너레이터는 제너레이터 객체에서 __next__ 메서드를 호출할 때마다 함수 안의 yield까지 코드를 실행하며 yield에서 값을 발생시킴(generate)

     

    yield의 동작 과정

    def number_generator():
        yield 0    # 0을 함수 바깥으로 전달하면서 코드 실행을 함수 바깥에 양보
        yield 1    # 1을 함수 바깥으로 전달하면서 코드 실행을 함수 바깥에 양보
        yield 2    # 2를 함수 바깥으로 전달하면서 코드 실행을 함수 바깥에 양보
    
    g = number_generator()
    
    a = next(g)    # yield를 사용하여 함수 바깥으로 전달한 값은 next의 반환값으로 나옴
    print(a)
    
    b = next(g)
    print(b)
    
    c = next(g)
    print(c)
    
    # 실행 결과
    
    0
    1
    2

     

    제너레이터와 return

    제너레이터는 함수 끝까지 도달하면 StopIteration 예외가 발생함

    마찬가지로 return도 함수를 끝내므로 return을 사용해 함수 중간에 빠져나오면 StopIteration 예외가 발생

    제너레이터 안에서 return에 반환값을 지정하면 예외의 에러 메시지로 들어감

    def one_generator():
        yield 1
        return 'return에 지정한 값'
    
    try:
        g = one_generator()
        next(g)
        next(g)
    except StopIteration as e:
        print(e)
        
    # 실행 결과
    return에 지정한 값

     

    제너레이터 만들기
    def number_generator(stop):
        n = 0              # 숫자는 0부터 시작
        while n < stop:    # 현재 숫자가 반복 끝낼 숫자보다 작을 때 반복
            yield n        # 현재 숫자 바깥으로 전달
            n += 1         # 현재 숫자 1씩 증가
    
    for i in number_generator(3):
        print(i)
    
    # 실행 결과
    
    0
    1
    2

     

    yield에서 함수 호출

    def upper_generator(x):
        for i in x:
            yield i.upper()    # 함수의 반환값을 바깥으로 전달
    
    fruits = ['apple', 'pear', 'grape', 'pineapple', 'orange']
    for i in upper_generator(fruits):
        print(i)
    
    # 실행 결과
    
    APPLE
    PEAR
    GRAPE
    PINEAPPLE
    ORANGE

     

    yield from으로 값을 여러 번 바깥으로 전달하기
    def number_generator():
        x = [1, 2, 3]
        for i in x:
            yield i
    
    for i in number_generator():
        print(i)
    
    # 실행 결과
    
    1
    2
    3

    지금까지는 위 코드처럼 yield로 값을 한 번씩 바깥으로 전달

    · yield from 반복가능한객체

    · yield from 이터레이터

    · yield from 제너레이터객체

    def number_generator():
        x = [1, 2, 3]
        yield from x    # 리스트에 들어 있는 요소를 한 개씩 바깥으로 전달
    
    for i in number_generator():
        print(i)
    
    # 실행 결과
    
    1
    2
    3

     

    yield from에 제너레이터 객체 지정

    def number_generator(stop):
        n = 0
        while n < stop:
            yield n
            n += 1
    
    def three_generator():
        yield from number_generator(3)    # 숫자를 세 번 바깥으로 전달
    
    for i in three_generator():
        print(i)
    
    # 실행 결과
    
    0
    1
    2

     

    제너레이터 표현식

    · (식 for 변수 in 반복가능한객체)

    리스트 표현식을 사용할 때 [](대괄호)를 사용했는데, 같은 리스트 표현식을 ()(괄호)로 묶으면 제너레이터 표현식이 됨

    리스트 표현식은 처음부터 리스트의 요소를 만들어 내지만 제너레이터 표현식은 필요할 때 요소를 만들어 내므로 메모리를 절약할 수 있음

    'Python' 카테고리의 다른 글

    데코레이터(장식자)  (0) 2023.10.25
    코루틴  (0) 2023.10.24
    이터레이터(반복자)  (0) 2023.10.24
    예외 처리  (0) 2023.10.23
    클래스(3)  (0) 2023.10.23
Designed by Tistory.