Sono nuovo in Python e nella programmazione funzionale. Sto usando la versione 2.7.6Prelevare un valore da una coroutine in Python, a.k.a. convertire la richiamata nel generatore
Sto usando il framework Tornado per fare richieste di rete asincrone. Da quello che ho imparato sulla programmazione funzionale, voglio che i miei dati scorrano attraverso il mio codice usando i generatori. Ho fatto la maggior parte di ciò di cui ho bisogno usando i generatori e trasformando i dati mentre passano attraverso le mie chiamate di funzione.
Alla fine del mio flusso, voglio fare una richiesta di REST per alcuni dati. Ho un ciclo for appena prima di inviare i miei dati a Tornado, avviare il pull e quindi inviare la richiesta http. L'oggetto http fornito da Tornado accetta una funzione di callback come opzione e restituisce sempre un futuro, che in realtà è un oggetto Tornado Future e non il futuro ufficiale di Python.
Il mio problema è che poiché ora sto usando i generatori per estrarre i miei dati attraverso il mio codice, non voglio più usare la funzione di callback. Il mio ragionamento per questo è che dopo aver recuperato i miei dati dalla richiamata, i miei dati vengono ora inseriti nel mio codice e non posso più utilizzare i generatori.
Il mio obiettivo è quello di creare un'interfaccia che appare in questo modo:
urls = (...generated urls...)
responses = fetch(urls)
Dove risposte è un generatore sopra gli URL completati.
Quello che ho tentato di fare, tra le molte cose, è convertire i risultati della richiamata in un generatore. Stavo pensando a qualcosa di simile, anche se sono ben lontano dall'implementarlo per altre questioni che spiegherò presto. Tuttavia, ho voluto il mio prendere la funzione di cercare qualcosa di simile:
def fetch(urls):
def url_generator():
while True:
val = yield
yield val
@curry
def handler(gen, response):
gen.send(response)
gen = url_generator()
for u in urls:
http.fetch(u, callback=handler(gen))
return gen
ho semplificato il codice e la sintassi di concentrarsi sul problema, ma ho pensato che questo stava per funzionare bene. La mia strategia era quella di definire una coroutine/generatore a cui manderò le risposte, così come le ricevo.
Quello che ho più problemi è la coroutine/generatore. Anche se definisco un generatore nel modo sopra descritto ed eseguo il seguente, allora ottengo un ciclo infinito - questo è uno dei miei problemi principali.
def gen():
while True:
val = yield
print 'val', val
yield val
print 'after', val
break
g = gen()
g.send(None)
g.send(10)
for e in g:
print e
Questa stampa val 10 after 10
nel coroutine come previsto con la rottura, ma il ciclo for non viene mai il valore di 10. E non stampa nulla, mentre la rottura è lì. Se rimuovo la pausa, poi ho la ciclo infinito:
val None
None
after None
None
val None
None
after None
None
...
Se rimuovo il ciclo for, allora la coroutine stamperà solo val 10
come si aspetta il secondo rendimento. Mi aspetto questo. Tuttavia, l'utilizzo non produce nulla.
Analogamente, se rimuovo il ciclo for e lo sostituisco con print next(g)
, ricevo un errore StopIteration, che presumo significa che ho chiamato su un generatore che non ha più valori.
Chiunque, io sono a una perdita completa mentre mi immergo in più profondità su Python. Immagino che questa situazione sia così comune in Python che qualcuno conosce un grande approccio. Ho cercato "converti il callback in generatore" e così, ma non ho avuto molta fortuna.
In un'altra nota, potrei cedere ogni futuro dalla richiesta http, ma non ho avuto molta fortuna "in attesa" del rendimento per il futuro da completare.Ho letto molto su "yield from", ma sembra essere specifico per Python 3 e Tornado non sembra funzionare ancora su Python 3.
Grazie per la visualizzazione, e grazie per l'aiuto che puoi fornire.
Impressionante domanda :). Ben scritto e ricercato. – Cyphase
Grazie. Questa è la mia prima domanda :) – Joe
Tornado funziona con python 3, è '@ curry' il tuo generatore? –