Liefert einen Wert aus einer Coroutine in Python, konvertiert den Callback in den Generator

9

Ich bin neu in Python und funktionaler Programmierung. Ich benutze Version 2.7.6

Ich verwende das Tornado-Framework, um asynchrone Netzwerkanforderungen zu stellen. Von dem, was ich über die funktionale Programmierung gelernt habe, möchte ich, dass meine Daten mit Hilfe von Generatoren durch meinen Code strömen. Ich habe das meiste getan, was ich brauche, indem ich Generatoren benutze und die Daten transformiere, während sie durch meine Funktionsaufrufe strömen.

Ganz am Ende meines Streams möchte ich für einige Daten eine REST-Anforderung stellen. Ich habe eine for-Schleife, kurz bevor ich meine Daten an Tornado übergebe, um den Pull zu initiieren und dann die http-Anfrage zu senden. Das von Tornado bereitgestellte http-Objekt nimmt eine Callback-Funktion als Option und gibt immer ein Future zurück - das eigentlich ein Tornado Future-Objekt und nicht das offizielle Python-Future ist.

Mein Problem ist, dass ich jetzt, da ich Generatoren verwende, um meine Daten durch meinen Code zu ziehen, die Callback-Funktion nicht mehr verwenden möchte. Mein Argument dafür ist, dass nachdem ich meine Daten vom Rückruf zurückgeholt habe, meine Daten jetzt durch meinen Code geschoben werden und ich keine Generatoren mehr benutzen kann.

Mein Ziel ist es, ein Interface zu erstellen, das so aussieht:

%Vor%

Wo Antworten die generierten URLs generieren.

Was ich versucht habe - unter vielen Dingen - ist, die Ergebnisse vom Callback in einen Generator umzuwandeln. Ich habe über so etwas nachgedacht, obwohl ich weit davon entfernt bin, es für andere Themen zu implementieren, die ich bald erklären werde. Ich wollte jedoch, dass meine Abruffunktion ungefähr so ​​aussieht:

%Vor%

Ich habe den Code und die Syntax vereinfacht, um mich auf das Problem zu konzentrieren, aber ich dachte, das würde gut funktionieren. Meine Strategie war es, eine Coroutine / Generator zu definieren, an die ich die Antworten dann senden werde, wenn ich sie erhalte.

Am meisten Probleme habe ich mit der Coroutine / Generator. Selbst wenn ich einen Generator auf die obige Weise definiere und folgendes mache, bekomme ich eine Endlosschleife - das ist eines meiner Hauptprobleme.

%Vor%

Dies gibt val 10 after 10 in der Coroutine wie erwartet mit der Pause aus, aber die for-Schleife erhält nie den Wert 10. Es wird nichts gedruckt, solange die Pause da ist. Wenn ich die Pause entferne, bekomme ich die Endlosschleife:

%Vor%

Wenn ich die for-Schleife entferne, dann druckt die Coroutine nur val 10 , während sie auf die zweite Ausbeute wartet. Ich erwarte das. Die Verwendung führt jedoch zu nichts.

Ähnlich, wenn ich die for-Schleife entferne und sie durch print next(g) ersetze, bekomme ich einen StopIterationsfehler, was bedeutet, dass ich als nächstes auf einem Generator anrief, der keine Werte mehr hat.

Anywho, ich bin völlig verloren, während ich tiefer in Python eintauche. Ich denke, das ist eine so häufige Situation in Python, dass jemand einen guten Ansatz kennt. Ich suchte nach "Callback in Generator umwandeln" und so, hatte aber nicht viel Glück.

Mit anderen Worten, ich könnte möglicherweise jede Zukunft aus der http-Anfrage herausholen, aber ich hatte nicht viel Glück, um auf den Ertrag für die Zukunft zu warten. Ich lese viel über 'yield from', aber es scheint Python 3 spezifisch zu sein und Tornado scheint noch nicht auf Python 3 zu funktionieren.

Vielen Dank für die Anzeige und danke für Ihre Hilfe.

    
Joe 07.08.2015, 04:12
quelle

1 Antwort

3

Tornado funktioniert gut auf Python 3.

Das Problem mit Ihrem vereinfachten Code oben ist, dass dies nicht das tut, was Sie erwarten:

%Vor%

Sie erwarten, dass der Generator dort pausiert (blockiert Ihre for-Schleife), bis eine andere Funktion g.send(value) aufruft, aber das passiert nicht. Stattdessen verhält sich der Code wie folgt:

%Vor%

So empfängt die for-Schleife None -Werte so schnell, wie sie verarbeitet werden können. Nachdem es jedes None erhalten hat, ruft es implizit g.next() auf, was dasselbe ist wie g.send(None) . Also, Ihr Code entspricht dem:

%Vor%

Wenn ich diese Version des Codes lese, wo das implizite Verhalten explizit gemacht wird, hoffe ich, dass es klar ist, warum es nur None in einer Endlosschleife erzeugt.

Was Sie brauchen, ist eine Möglichkeit, eine Funktion zum Hinzufügen von Elementen zum Kopf einer Warteschlange hinzuzufügen, während eine andere Funktion blockiert, auf Elemente zu warten, und sie aus der Warteschlange zieht, wenn sie fertig sind. Ab Tornado 4.2 haben wir genau das:

Ссылка

Das Webspider-Beispiel ist nahe an dem, was Sie tun möchten, ich bin mir sicher, dass Sie es anpassen können:

Ссылка

    
A. Jesse Jiryu Davis 07.08.2015 09:05
quelle