ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [코딩도장] day27. 파이썬 제너레이터 사용하기 - yield
    IT/파이썬 2020. 9. 21. 22:21

    출처 : unsplash

     

    ■ 들어가기

    - 파이썬 코딩 도장 (남재윤/길벗). 을 공부하며 정리하는 블로그


    ▶ Unit40. 제너레이터 사용하기

         - 40.1 제너레이터와 yield 알아보기

         - 40.2 제너레이터 만들기

         - 40.3 yield from으로 값을 여러 번 바깥으로 전달하기

     

     

    0. 들어가기

    - 제너레이터는 이터레이터를 생성해주는 함수
    - 이터레이터는 클래스에 __iter__, __next__, __getitem__ 메서드를 구현해야 하는 반면
    - 제너레이터는 함수 안에서 yield 라는 키워드만 사용하면 됨

     

     

    >> 40.1 제너레이터와 yield 알아보기 <<

    - 사용법 : yield 값

    목적 : yield에 대해 알아본다.
    소스 (yield.py) 결과
    def number_generator() :
        yield 0
        yield 1
        yield 2

    for i in number_generator() :
        print(i)
    0
    1
    2

     

    1. 제너레이터 객체가 이터레이터인지 확인하기

    - dir 함수로 메서드 목록 확인

    - 목록 중 __iter__ 가 있다면 이터레이터 가능 객체

    >>> g = number_generator()
    >>> g
    <generator object number_generator at 0x02A93030>
    >>> dir(g)
    ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__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_yieldfrom', 'send', 'throw']

    - 제너레이터 객체 g의 __next__ 를 호출하면 이터레이터와 마찬가지로 0, 1, 2가 반환되며 이후 StopIteration 예외 발생

    >>> g.__next__()
    0
    >>> g.__next__()
    1
    >>> g.__next__()
    2
    >>> g.__next__()
    Traceback (most recent call last):
      File "<pyshell#85>", line 1, in <module>
        g.__next__()
    StopIteration

     

    2. for와 제너레이터

    출처 : 파이썬 코딩 도장 (dojang.io)

    - 제너레이터 함수를 통해 제너레이터 객체(이터레이터)가 호출되면 yield에 정의된 값을 반환
    - 현재 함수를 잠시 중단하고 함수 바깥의 코드가 실행되도록 한다..... √ 무슨 말인지 모르겠음..;;

     

     

    3. yield의 동작 과정 알아보기

    - 사용법
    변수 = next(제너레이터객체)

    목적 : yield 동작 과정을 알아본다.
    소스 (yield_next.py) 결과
    def number_generator() :
        yield 0
        yield 1
        yield 2

    g = number_generator()

    a = next(g)
    print(a)

    b = next(g)
    print(b)

    c = next(g)
    print(c)
    0
    1
    2

     

     

    >> 40.2 제너레이터 만들기 <<

    - range(횟수)와 같이 동작하는 기능 구현

    목적 : 시퀀스 자료형인 range(횟수)와 동일한 기능을 하는 함수 확인
    소스 (generator.py) 결과
    def number_generator(stop) :
        n = 0   # 숫자는 0부터 시작
        while n < stop :
            yield n
            n += 1

    for i in number_generator(3) :
        print(i)
    0
    1
    2

    - number_generator 함수의 인자값으로 3을 건넸으므로 0, 1, 2 3번 발생함
    - yield가 3번 나오므로 for 반복문도 3번 반복

     

     

    1. yield에서 함수 호출하기

    소스 (generator_yield_function.py) 결과
    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

    - 만약 upper_generator 함수 내 yield 말고 print(i.upper())로 하면 안될까??

    >> 출력은 되는데 마지막에 TypeError 발생! 왜??

    Traceback (most recent call last):
      File "C:/project/generator_yield_function.py", line 11, in <module>
        for i in upper_generator(fruits) :
    TypeError: 'NoneType' object is not iterable

     

     

    >> 40.3 yield from으로 값을 여러 번 바깥으로 전달하기 <<

    - yield 뒤에 값을 한 개씩 지정 가능하므로 여러 번 바깥으로 전달 필요 시 for/while 반복문 사용
    - BUT, yield from 키워드로 반복 출력할 변수만 지정하면 ok!
    - 단, 파이썬 3.3버전 이상부터 가능하며 "반복 가능한 객체", "이터레이터", "제너레이터" 객체를 지정
    - 사용법
    yield from 반복가능한객체
    yield from 이터레이터
    yield from 제너레이터객체

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

    for i in number_generator() :
        print(i)
    1
    2
    3

     

    1. yield from에 제너레이터 객체 지정하기

    소스 (generator_yieldl_from_generator.py) 결과
    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

     

     

    댓글

Designed by Tistory.