2014-09-17 18 views
12

In Python maggior parte degli esempi di resa da spiegare con dicendo cheDifferenza tra `resa da foo()` e `for x in foo(): resa x`

yield from foo() 

è simile a

for x in foo(): yield x 

D'altra parte non sembra essere esattamente lo stesso e c'è un po 'di magia lanciata. Mi sento un po' a disagio nell'usare una funzione che fa magie che non capisco. Che cosa devo sapere sulla magia di yield from per evitare di entrare in una situazione in cui la magia fa qualcosa che non mi aspetto? Quali vantaggi offre la magia, di cui dovrei essere a conoscenza?

+4

Vedere [PEP-380] (http://legacy.python.org/dev/peps/pep-0380/). – jonrsharpe

+1

Domanda correlata: http://stackoverflow.com/questions/24033577/difference-between-generator-expression-and-generator-function – Bakuriu

risposta

13

Quando foo() restituisce un normale iterabile, i due sono equivalenti. La "magia" entra in gioco quando foo() è un generatore . In quel momento, i casi yield from foo() e for x in foo(): yield x differiscono materialmente.

Un generatore può essere inviato dati, utilizzando il generator.send() method. Quando si utilizza il ciclo for, l'espressione yield x "riceve" i dati inviati; il generatore foo() non vedrà mai questo. Ma quando si utilizza yield from i dati inviati vanno direttamente a qualsiasi espressione yield il generatore delegato è attualmente in pausa a. In altre parole, yield from passa i dati inviati in modo che il generatore delegato possa riceverlo.

È inoltre possibile aumentare le eccezioni in un generatore, con generator.throw(); con il caso di loop for, l'eccezione viene sollevata dalla riga yield x, mentre con yield from l'eccezione viene nuovamente inoltrata; l'eccezione viene sollevata all'interno di foo().

Insieme, ciò significa che yield fromnella sostanza sostituisce il generatore corrente per la durata dell'iterazione delegata.

Il delegato-al generatore ottiene anche per comunicare con il generatore genitore, quando fatto l'attributo .value di eccezione StopIteration sollevata viene restituito come valore della yield from espressione. È possibile impostare il valore di tale eccezione utilizzando return <expression> nel generatore delegato a foo() oppure è possibile utilizzare raise StopIteration(<expression>) in modo esplicito.

yield from è stato introdotto nella lingua con PEP 380: Syntax for Delegating to a Subgenerator.

+1

+1 per la semplice spiegazione. 'yield from' consente di rifattorizzare un generatore in più funzioni senza modificare il comportamento del codice (sebbene i generatori nidificati non siano ancora ottimizzati per quanto ne so, ad esempio,' O (n * k) 'il comportamento è possibile se si è implementando un power set invece di 'O (n)' dove 'n = 2 ** k'). – jfs

+0

Questo ha posto le fondamenta della tua risposta: _ "Quando' foo() 'restituisce un normale iterabile, i due sono equivalenti.La" magia "entra in gioco quando' foo() 'è anche un generatore." _ Vuoi delegare a un altro generatore? Usa 'rendimento da'. – sargas