Come vengono implementati i generatori e le coroutine in cpython?
Domanda
Ho letto che in Cpython, l'interprete (l'elenco delle funzioni di Python chiamato per raggiungere questo punto) è miscelato con lo stack C (l'elenco delle funzioni C che sono state chiamate nel codice dell'interprete). In tal caso, come vengono implementati i generatori e le coroutine? Come ricordano il loro stato di esecuzione? Cpython copia lo stack di ogni generatore / coroutine da e per uno stack del sistema operativo? O Cpython mantiene semplicemente il telaio più alto del generatore sul heap, poiché il generatore può produrre solo da quel telaio più alto?
Soluzione
Il yield
L'istruzione prende l'attuale contesto di esecuzione come chiusura e lo trasforma in un oggetto vivente. Questo oggetto ha un file __iter__
Metodo che continuerà dopo questa dichiarazione di rendimento.
Quindi lo stack di chiamata viene trasformato in un oggetto heap.
Altri suggerimenti
L'idea che lo stack di Python e lo stack C in un programma Python in esecuzione siano mescolati può essere fuorviante.
Lo stack Python è qualcosa di completamente separato rispetto allo stack C reale utilizzato dall'interprete. Le strutture di dati su Python Stack sono in realtà oggetti "frame" di Python full (che possono persino essere introspeuti e avere alcuni attributi modificati in tempo di esecuzione). Questo stack è gestito dalla macchina virtuale Python, che a sua volta funziona in C e quindi ha un normale programma C, livello della macchina, stack.
Quando si utilizzano generatori e iteratori, l'interprete memorizza semplicemente il rispettivo telaio da qualche altra parte rispetto allo stack del programma Python e lo spinge lì quando riprende l'esecuzione del generatore. Questo "altrove" è l'oggetto del generatore stesso. Chiamare il metodo "Avanti" o "Invia" sull'oggetto generatore fa sì che ciò accada.