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.
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.
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.