[python] 생성기의 제작 방법과 사용 방법

13513 단어 Pythontech

생성기란


생성기는 아무것도 없는 곳에서 균형기를 만드는 것이다.
가장 큰 특징은 실행 지연이다.
이 특징은 무한히 긴 수열을 나타낼 수 있다.

원래 이른바 균형기


컬렉션(리스트와 모듈 등 수치의 집합)에서 요소를 하나하나 추출하는 디자인 모델입니다.
다음은 균형기 사용과 사용하지 않을 때의 for문의 구체적인 예를 살펴보자.
python의 for 문장은 내부에서 균형기를 생성하고 사용합니다.
lst = [0, 1, 2, 3]
# lstからイテレータを生成し、中身を1つずつ取り出している
for i in lst:
    print(i)
균형기를 사용하지 않는 for문은python으로 쓸 수 없기 때문에 js의 예입니다.
const array = [0, 1, 2, 3]
const n = 4
for (let i = 0; i < array.length; i++) {
    // array全体に対して、インデックスでアクセスしている。
    console.log(array[i])
}
균형기를 사용할 때 균형기를 통해 모음집에서 값을 하나씩 꺼낸다.
다른 한편, 균형기를 사용하지 않으면 색인을 통해 수집 주체에 접근하거나 pop() 등의 방법으로 값을 꺼낼 수 있다.

방법·사용법


간단한 예로부터 최종적으로 생성기로 피보나치 수열을 실현한다.

예1: 1, 2, 3의 생성기를 되돌려줍니다


# ジェネレータ関数は普通の関数とは異なるのでそれが分かる命名がよい
def gen_123():
    print('egg')
    yield 1  # 1回目のnextでここまで実行
    print('and')
    yield 2  # 2回目のnextでここまで実行
    print('spam')
    yield 3  # 3回目のnextでここまで実行
    print('hum')  # 4回目のnextで実行されるが次にyieldがないのでStopIterationを投げる


if __name__ == "__main__":
    # ジェネレータ関数からジェネレータを生成
    gen = gen_123()
    # ジェネレータを1つ目のyieldまで実行
    first = next(gen)
    # firstには1回目のyieldの値が入る
    print(first)
    second = next(gen)
    print(second)
    third = next(gen)
    print(third)
    fourth = next(gen)  # !StopIteration
출력
egg
1
and
2
spam
3
hum
Traceback (most recent call last):
  File "hoge.py"
    fourth = next(gen)  # !StopIteration
StopIteration
next(gen)는 다음yield까지 진행해 달라는 명령이다.
StopIteration은 "gen 만들어서 생성기를 추진했지만 다음에 돌아올 값이 없다"는 메시지다.
참고로 for문은 next(gen) 오른쪽에 쓴 식의 결과로 균형기를 생성하여 StopIteration이 균형기in에 던져지기 전에 실행하고 수치를 꺼낸다.

예2: 1 무한 반환 생성기


def gen_1():
    # 無限ループを作成
    while True:
        # next()されると常に1が返る
        yield 1
        # 無限ループなので、次のyieldが必ず存在する
        # つまり、gen_1()はStopIterationを返さない


if __name__ == "__main__":
    count = 0
    # gen_1()はStopIterationを返さないので無限ループになる
    for i in gen_1():
        # 無限ループ防止
        if count > 10:
            break
        print(i)
        count += 1
출력
1
1
1
1
・
・
・
는 무한 순환과 생성기 함수를 통해 무한 연속의 수열을 나타낼 수 있다.

예3: 피보나치 수열


import itertools


def gen_fib():
    """前の値(prev)と今の値(current)を足した値が次の値"""
    # 前の値
    prev = 1
    # 1回目のyieldでは1が取り出される
    yield prev
    # 今の値
    current = 1
    # 2回目のyieldも1が取り出される
    yield current
    # フィボナッチ数列には終わりがないので無限ループ
    while True:
        # 今の値を(今の値 + 前の値), 前の値を今の値に更新
        current, prev = current + prev, current
        # 更新された今の値が返る
        yield current


if __name__ == "__main__":
    # itertools.takewhileを使うことで、
    # 無限に続く数列から、条件から外れるまでの値を取り出せる
    # 100より小さいフィボナッチ数
    print(list(itertools.takewhile(lambda n: n < 100, gen_fib())))

    # itertools.isliceを使うことで、
    # 無限に続く数列からインデックスで指定した範囲を取り出せる
    # 101番目~110番目のフィボナッチ数
    print(list(itertools.islice(gen_fib(), 100, 110)))

    # itertools.isliceで生成したイテレータに対して、
    # 1回だけnextを適応することで、特定のインデックスの値を取り出せる
    # 100,001番目のフィボナッチ数は何桁?
    print(len(str(
        next(itertools.islice(gen_fib(), 100_000, None)))))
출력
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
[573147844013817084101, 927372692193078999176, 1500520536206896083277,
2427893228399975082453, 3928413764606871165730, 6356306993006846248183,
10284720757613717413913, 16641027750620563662096, 26925748508234281076009,
43566776258854844738105] ← 見やすいように改行している
20899
피보나치 수열은 무한히 연장된 수열이다.따라서 next()라고 쓰면 무한순환에 빠진다.
이번 예에서 균형기 구축을 위한 표준 라이브러리list(gen_fib())를 사용하여 유한한 균형기를 새로 생성하여 목록을 만들었고 실제로는 수치를 추출했다.

최후


생성기로 활약하는 장면으로 무한히 뻗은 피포나치 수열에서 특정 값을 꺼내는 처리를 소개했다.
이걸 일반화하면 itertools될 거예요.
나는 이 글이python에서 프로그래밍을 할 때 생성기를 떠올리는 데 도움을 줄 수 있다고 생각한다.

좋은 웹페이지 즐겨찾기