概要

緑さん「ふふーん。今日はジェネレータを作って遊んじゃうぜ。いやー、これはレベル高いぜ」

def my_generator():
    yield "最初の文字列"
    yield "次の文字列"
    yield "最後の文字列"

緑さん「ふふーん。レベル高いから、型も書いちゃおうかなー。ま、まあここは ChatGPT ちゃんにお願いしよう (震え声)」

from collections.abc import Generator

def my_generator() -> Generator[str, None, None]:
    yield "最初の文字列"
    yield "次の文字列"
    yield "最後の文字列"

緑さん「ハァ?! なんだ str のあとの None, None って……?!」

1日1 Python のお時間です。

 

みっつの型の説明が書いてあるとこ

A generator can be annotated using the generic type Generator[YieldType, SendType, ReturnType].

みっつの型は、 YieldType, SendType, ReturnType っていうのね。

 

YieldType と ReturnType はまあ簡単

  • YieldType が yield で返すやつ
  • ReturnType が return で返すやつ (= StopIteration に持たせる値)
# NOTE: よく from typing import Generator と書かれるけど、それは非推奨ってここ↓に書いてある。
#       https://docs.python.org/ja/3/library/typing.html#typing.Generator
from collections.abc import Generator

# YieldType (yield で返す値)
# ReturnType (return で返す値)
# ……を埋めたもの。
def my_generator() -> Generator[str, None, int]:
    yield "最初の文字列"
    yield "次の文字列"
    return 999  # return すると StopIteration の値になる

gen = my_generator()
try:
    print(next(gen))  # --> 最初の文字列
    print(next(gen))  # --> 次の文字列
    print(next(gen))  # --> StopIteration(999)
except StopIteration as e:
    print(e.value)  # --> return の値: 999

 

SendType がムズい

from collections.abc import Generator

# SendType (send で受け取る値)
def my_generator() -> Generator[str, int, None]:
    # まず next して、その次に send した値が、 yield の返り値になる。
    received = yield "最初の文字列"
    yield str(received)

gen = my_generator()
print(next(gen))  # --> '最初の文字列'
print(gen.send(123))  # --> '123'

まず next して、その次に send した値が、 yield の返り値になる。

いやもう、 yield は出力だけをするもの、と理解している緑さんにとって “yield の返り値” っていうフレーズがもうムズい。さらに……

  • 最初っから send(123) は不可能。 (send → send は基本、不可能。)
  • でも send(None) なら OK。 (send(None) → send は OK。)

……というような隠れ仕様もムズい。なかなかよい Python コア知識をゲットしちゃったね。

send のドキュメントはこちら↓

 

おしまい

ジェネレータとの出会いはおよそ9年前。

当時は yield だけに圧倒されていたが、現在では Generator さんとの間合いを詰め、 send とかいうバケモンと鍔迫り合いができるくらいにはなったか。