2017-02-12 5 views
17

Für eine lange Zeit wusste ich nicht, dass Sie return nicht vor einer Yield-Anweisung setzen können. Aber eigentlich können Sie:Wann verwenden Sie Rendite (etwas zurückgeben)?

def gen(): 
    return (yield 42) 

, der

ähnlich ist
def gen(): 
    yield 42 
    return 

und die einzige Nutzung ich denken kann sind, gesendet Wert StopIteration anhänge: pep-0380

Rückkehr ausdr in einem Generator bewirkt, dass StopIteration (expr) beim Verlassen des Generators ausgelöst wird.

def gen(): 
    return (yield 42) 

g = gen() 
print(next(g)) # 42 
try: 
    g.send('AAAA') 
except StopIteration as e: 
    print(e.value) # 'AAAA' 

Dies kann aber auch mit einem zusätzlichen variablen erfolgen, was deutlicher ist:

def gen(): 
    a = yield 42 
    return a 

g = gen() 
print(next(g)) 
try: 
    g.send('AAAA') 
except StopIteration as e: 
    print(e.value) # 'AAAA' 

So scheint es return (yield xxx) ist lediglich ein syntaktischer Zucker. Fehle ich etwas?

+3

"Dies kann aber auch mit einer zusätzlichen Variablen geschehen, die expliziter ist" - das könnte man zu jeder 'return' Aussage sagen. 'return x + y 'wird zu z = x + y; z zurückgeben.'return foo()' wird 'x = foo(); gib x zurück. Es gibt nichts Spezifisches für "Rückkehr (Ausbeute was auch immer)" hier. – user2357112

+0

Bei 'StopIteration'-Argumenten wird nicht explizit auf diese zugegriffen. Genau so werden die 'yield from'-Ausdrücke implementiert. Es ist ein veröffentlichter Teil der API, aber normalerweise kein interessanter Teil. – user2357112

Antwort

4

Innerhalb eines Generators der Ausdrücke (42 Ausbeute) den Wert 42 ergeben, aber es gibt auch einen Wert, der entweder keine ist, wenn Sie verwenden next(generator) oder einen bestimmten Wert, wenn Sie generator.send(value) verwenden.

So wie Sie sagen, Sie könnten einen Zwischenwert verwenden, um das gleiche Verhalten zu erhalten, nicht, weil dies syntaktischer Zucker ist, sondern weil die Yield-Ausdrücke den Wert, den Sie senden, buchstäblich zurückgeben.

Sie könnten ebenso etwas wie

def my_generator(): 
    return (yield (yield 42) + 10) 

tun Wenn wir dies nennen, die Reihenfolge der Anrufe mit:

g = my_generator() 
print(next(g)) 
try: 
    print('first response:', g.send(1)) 
    print('Second response:', g.send(22)) 
    print('third response:', g.send(3)) 
except StopIteration as e: 
    print('stopped at', e.value) 

Zuerst haben wir die Ausgabe von 42 erhalten, und der Generator im Wesentlichen pausiert in Ein Zustand, den man beschreiben könnte: return (yield <Input will go here> + 10), Wenn wir dann g.send(1) aufrufen, bekommen wir den Ausgang 11. und der Generator ist jetzt im Zustand: return <Input will go here>, dann senden g.send(22) wird eine StopIteration(22) werfen, wegen der Art und Weise, wie die Rückgabe in Generatoren gehandhabt wird. So kommen Sie wegen der Ausnahme nie zum dritten senden.

Ich hoffe, dieses Beispiel macht es ein bisschen mehr offensichtlich, wie yield in Generatoren funktioniert und warum die Syntax return (yield something) nichts besonderes oder exotisch ist und genau so funktioniert, wie Sie es erwarten würden.

Wie für die wörtliche Frage, wann würdest du das tun? Nun, wann immer Sie etwas liefern wollen, und dann später eine StopIteration zurückgeben, die die Eingabe des an den Generator gesendeten Benutzers widerspiegelt. Denn das ist buchstäblich das, was der Code sagt. Ich erwarte, dass solches Verhalten sehr selten gewünscht wird.

+0

Interessant. Wenn ich etwas wie "x = (yield 42)" und "yield x + 10" mache, benutze 'g.send', es scheint,' x' wird 'None', ist das zu erwarten? Warum wird "x" nicht zu dem, was ich an "send" weitergegeben habe? –

+0

@ juanpa.arrivillaga Es tut mir leid, aber du musst einen Code veröffentlichen, der zeigt, was du tust. Wenn Sie das, was Sie richtig schreiben, zusammensetzen, erhalten Sie die erwarteten Ergebnisse. Wahrscheinlich werden Sie es nicht richtig zusammensetzen, da es nicht für Sie arbeitet. – jVincent

0

Ertrag ist wie Rückkehr - es gibt zurück, was auch immer Sie ihm sagen. Der einzige Unterschied besteht darin, dass beim nächsten Aufruf der Funktion die Ausführung ab dem letzten Aufruf der Yield-Anweisung beginnt.

Verwandte Themen