[PYTHON] "Inline" Sublime Text Plug-In Rückrufe im Generator

Überblick

Der Prozess der Verwendung der verschiedenen Eingabeschnittstellen von Sublime Text ist in der Regel ein Rückruf, also habe ich ihn ordentlich mit einem Generator geschrieben! Es ist eine Geschichte. Ich benutze das Plug-In, das ich gerade schreibe.

Hintergrund

Mit der Sublime Text 3-API können Sie die meisten gewünschten Aufgaben über einen Texteditor ausführen. Es ist möglich, verschiedene Eingaben zu akzeptieren, z. B. das Anzeigen eines Schnellfensters mit benutzerdefinierten Menüelementen und das Anzeigen eines Texteingabefelds. Wie Sie jedoch sehen können, akzeptiert der Editor Eingaben von verschiedenen Benutzern Andere Operationen sind nicht blockiert, oder? Natürlich werden die Funktionen, die diese Eingangsempfangsschnittstellen bedienen, in einem neuen Thread ausgeführt, aber wenn Sie die Verarbeitung des Hauptthreads von dort aus stören möchten, nachdem Sie die im Voraus übergebene Rückruffunktion eingegeben haben Rufen Sie an mit.

In der Schnellanzeige sieht es beispielsweise so aus:

from sublime_plugin import WindowCommand


class ShowMenu(WindowCommand):

    def run(self):
        menu = ["A", "B", "C"]
        def cb(index):
            print(menu[index])
        self.window.show_quick_panel(menu, cb)

Kann ein Menü anzeigen, das die Elemente "A", "B", "C" enthält, und der Funktion "cb ()" wird der Index des ausgewählten Menüs übergeben. Nun, es ist keine große Sache, weil der Inhalt des Rückrufs klein ist, aber wenn die Anzahl der Zeilen des Rückrufs und die Anzahl der Variablen, die an den Rückruf übergeben werden, zunehmen, wird es wieder problematisch. Noch problematischer ist es, wenn Sie Befehle aufrufen müssen, die nacheinander auf Benutzereingaben warten, und wenn Sie versuchen, den nächsten Wartebefehl für Benutzereingaben mit einem entsprechenden Rückruf im Rückruf aufzurufen ... Zum Beispiel:

class Auth(WindowCommand):

    def run(self):
        self.window.show_input_panel("username", "", cb1)
        #Wenn das Eingabefeld angezeigt wird, wird die Zeile auf dieser Seite fortgesetzt, ohne auf die Eingabe zu warten.
        #Schreibverarbeitung unter Verwendung der Eingabe im Rückruf


def _cb1(username):
    # show_input_panel()Wenn es so bleibt, wie es ist, wird die eingegebene Zeichenfolge angezeigt und das ist es wirklich, aber im Moment ist es mir egal
    self.window.show_input_panel(
        "password", "", functools.partial(_cb2, username))


def _cb2(username, password):
    _auth(username, password)


def _auth(username, password):
    #Authentifizierungsprozess mit Benutzername und Passwort

Nun, ich kann es schreiben, aber es ist nicht leicht zu lesen. Es ist mühsam und nicht intuitiv, sich als Funktion trennen zu müssen, um sie als Rückruf auszuführen, obwohl die als Funktion auszuschneidende Einheit nicht geeignet ist. Wenn viele Parameter übergeben werden müssen, ist dies problematisch und die Wartbarkeit wird verringert.

Schreiben wir eleganter

Kannst du nicht eleganter schreiben? ……Kann schreiben. Mit Python.

Im Prinzip wäre es gut, wenn die Ausführung der Funktion angehalten werden könnte, wenn auf die Eingabe durch den Benutzer gewartet werden soll. ――Ja, hier kommt die "Yield" -Anweisung ins Spiel. Durch Aufrufen der Anweisung "ield "können Sie den laufenden Zustand speichern, bis die Funktion" next () "oder die Funktion" send () "für den Generator aufgerufen wird. Wenn vom Benutzer Eingaben gemacht werden, können diese mithilfe der Funktion send () im Ausdruck im Generator verwendet werden. Wenn nicht, rufen Sie einfach next () auf. Also werde ich zuerst einen Dekorateur wie diesen vorbereiten.


def chain_callbacks(
    f: Callable[..., Generator[Callable[Callable[...]], Any, Any]
) -> Callable[..., None]:
    @wraps(f)
    def wrapper(*args, **kwargs):
        chain = f(*args, **kwargs)
        try:
            next_f = next(chain)
        except StopIteration:
            return

        def cb(*args, **kwargs):
            nonlocal next_f
            try:
                if len(args) + len(kwargs) != 0:
                    next_f = chain.send(*args, **kwargs)
                else:
                    next_f = next(chain)
                next_f(cb)
            except StopIteration:
                return
        next_f(cb)
    return wrapper

Es ist ein wenig knifflig, aber Sie können es verwenden, um Ihre Rückrufe zu "inline". Übergeben Sie in der Anweisung "Yield" eine Funktion, die eine Rückruffunktion verwendet, für die die Anweisung "Yield" und nachfolgende Anweisungen beim Aufruf ausgeführt werden sollen ". Wenn ein Wert an diese Rückruffunktion übergeben wird, kann er als Rückgabewert von "Yield" empfangen werden.

from functools import partial

class Auth(WindowCommand):

    @chain_callback
    def run(self):
        # `functools.partial()`Mit`on_done`Nehmen Sie nur ein Argument
        #In Form einer Funktion ergeben
        username = yield partial(
            self.window.show_input_panel, "username", "",
            on_change=None, on_cancel=None)
        password = yield partial(
            self.window.show_input_panel, "password", "",
            on_change=None, on_cancel=None)
        #Von hier aus erfolgt der Authentifizierungsprozess mit Benutzername und Passwort

Diese Seite ist erfrischend!

Diese Verwendung von Generatoren wird auch in Web-Frameworks wie "Twisted" und "Tornado" verwendet.

Recommended Posts

"Inline" Sublime Text Plug-In Rückrufe im Generator
Erstellen Sie mit Sublime Text3 eine Python3-Build-Umgebung
Pythonbrew mit erhabenem Text
Richten Sie mit Sublime Text 2 eine Python-Entwicklungsumgebung ein
Erstellen Sie ein Plug-In, das in Sublime Text 2 immer beliebigen Text hervorhebt
GOTO in Python mit erhabenem Text 3
Aktivieren Sie Python raw_input mit Sublime Text 3
Erstellen Sie eine große Textdatei mit Shellscript
Ich habe einen Hanko-Generator mit GAN gemacht
Erstellen Sie eine Matrix mit PythonGUI (Textfeld)
Ich habe ein Paket wie das Weblio-Popup-Wörterbuch Englisch-Japanisch mit Sublime Text3 erstellt
Erstellen Sie ein Plugin, mit dem Sie in Python nach Registerkarten für Sublime Text 3 suchen können
Mit OpenJtalk auf Japanisch sprechen (Textdatei lesen)
Mit gTTS auf Japanisch sprechen (Textdatei lesen)
Erstellen Sie mit Flask einen einfachen Punktbildgenerator
Plugin zum Hinzufügen variabler Symbole (Sublime Text) Beschreibung
Ich habe versucht, es ein- und auszuschalten, indem ich "Ein Plug-In erstellen, das Leerzeichen mit Sublime Text 2 in voller Breite hervorhebt" eingestellt habe.
So erstellen Sie ein Untermenü mit dem Plug-In [Blender]
[Blender] Ergänzen Sie die Python-API von Blender mit einem Texteditor
Links, um mit Sublime Text zu tun, was Sie wollen
Verwenden Sie Python-Programme mit dem Ausführungs-Plugin exec_filter von fluentd
Verwenden Sie Python, das von Pyenv mit Sublime REPL von Sublime Text 3 installiert wurde
Verwenden Sie Python-Programme mit dem exec Output Plugin von fluentd