高校物理160203 views
りんご209490 views
中学英語811710 views
中学理科1630641 views
LaTeX962153 views
高校化学2924392 views
ヒストリア290598 views
高校倫理1440106 views
中学社会668760 views
世界の国564520 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python の send() でジェネレータに値を送る

ジェネレータは値を yield で返すだけでなく、send() メソッドを使って外部から値を受け取ることもできます。これにより、ジェネレータと呼び出し側で双方向のコミュニケーションが可能になります。

send() の基本

send() を使うと、yield 式の結果として値を渡せます。

def receiver():
    while True:
        received = yield
        print(f"受け取った: {received}")

gen = receiver()
next(gen)           # 最初の yield まで進める
gen.send("Hello")   # 受け取った: Hello
gen.send("World")   # 受け取った: World

最初に next() を呼び出すのは、ジェネレータを最初の yield まで進めるためです。これを「プライミング」と呼びます。

yield 式の値

yield は式として値を持ちます。send() で送った値が yield の評価結果になります。

def echo():
    result = None
    while True:
        received = yield result
        result = f"echo: {received}"

gen = echo()
print(next(gen))       # None(初期値)
print(gen.send("A"))   # echo: A
print(gen.send("B"))   # echo: B

next() と send(None) の関係

next(gen)gen.send(None) と同じです。

def simple():
    value = yield 1
    print(f"value = {value}")
    yield 2

gen = simple()
print(next(gen))        # 1
print(gen.send(None))   # value = None → 2

実用例:移動平均の計算

send() を使って、リアルタイムで移動平均を計算するジェネレータを作れます。

def moving_average(window_size):
    values = []
    average = None
    while True:
        value = yield average
        values.append(value)
        if len(values) > window_size:
            values.pop(0)
        average = sum(values) / len(values)

ma = moving_average(3)
next(ma)  # プライミング

print(ma.send(10))  # 10.0
print(ma.send(20))  # 15.0
print(ma.send(30))  # 20.0
print(ma.send(40))  # 30.0(10が除外される)

プライミングを自動化するデコレータ

毎回 next() を呼ぶのは面倒なので、デコレータで自動化できます。

def coroutine(func):
    def wrapper(*args, **kwargs):
        gen = func(*args, **kwargs)
        next(gen)  # 自動でプライミング
        return gen
    return wrapper

@coroutine
def receiver():
    while True:
        received = yield
        print(f"受け取った: {received}")

gen = receiver()  # next() 不要
gen.send("Hello")

throw() と close()

ジェネレータに例外を送ったり、終了させたりすることもできます。

def careful_gen():
    try:
        while True:
            value = yield
            print(f"処理: {value}")
    except GeneratorExit:
        print("ジェネレータ終了")
    except ValueError as e:
        print(f"エラー: {e}")

gen = careful_gen()
next(gen)
gen.send("A")       # 処理: A
gen.throw(ValueError, "不正な値")  # エラー: 不正な値
gen = careful_gen()
next(gen)
gen.close()  # ジェネレータ終了

コルーチンとしての活用

send() を活用すると、ジェネレータをコルーチン(協調的なタスク)として使えます。ただし、Python 3.5以降では async/await 構文が推奨されています。send() は主にレガシーコードや特殊なケースで使われます。