Heim  >  Artikel  >  Backend-Entwicklung  >  Entwerfen eines reinen Python-Web-Frameworks

Entwerfen eines reinen Python-Web-Frameworks

DDD
DDDOriginal
2024-09-19 06:21:33642Durchsuche

Webentwicklung ist einer der beliebtesten Anwendungsfälle für die Programmierung. Python ist eine der beliebtesten Programmiersprachen der Welt. Warum können wir also keine Web-Apps in Python erstellen?

Das Erstellen einer Benutzeroberfläche sollte einfach sein, aber selbst wenn Sie großartige Ingenieure in Ihrem Team haben, war der Aufwand für das Erlernen einer neuen Sprache und neuer Tools eine große Hürde. Oft kann die Erstellung einer Benutzeroberfläche schwieriger sein als die eigentliche Arbeit!

TLDR

Unter der Haube kompilieren sich Reflex-Apps zu einer React-Frontend-App und einer FastAPI-Backend-App. Nur die Benutzeroberfläche ist mit Javascript kompiliert. Die gesamte App-Logik und Statusverwaltung bleibt in Python und wird auf dem Server ausgeführt. Reflex verwendet WebSockets, um Ereignisse vom Frontend an das Backend zu senden und um Statusaktualisierungen vom Backend an das Frontend zu senden.

Bestehende Python-Lösungen

Es gab bereits einige Möglichkeiten, Apps in Python zu erstellen, aber keine davon entsprach unseren Anforderungen.

Einerseits gibt es Frameworks wie Django und Flask, die sich hervorragend zum Erstellen von Web-Apps in Produktionsqualität eignen. Aber sie kümmern sich nur um das Backend – Sie müssen weiterhin JavaScript und ein Frontend-Framework verwenden und eine Menge Boilerplate-Code schreiben, um das Frontend und das Backend zu verbinden.

Andererseits können reine Python-Bibliotheken wie Dash und Streamlit großartig für kleine Projekte sein, aber sie sind auf einen bestimmten Anwendungsfall beschränkt und verfügen nicht über die Funktionen und die Leistung, um eine vollständige Web-App zu erstellen. Wenn Ihre App an Funktionen und Komplexität zunimmt, stoßen Sie möglicherweise an die Grenzen des Frameworks. An diesem Punkt müssen Sie entweder Ihre Idee einschränken, damit sie in das Framework passt, oder Ihr Projekt verwerfen und es mit einem „echten Web-Framework“ neu erstellen.

Wir möchten diese Lücke schließen, indem wir ein Framework schaffen, das einfach und intuitiv zu nutzen ist und gleichzeitig flexibel und leistungsstark bleibt, um jede App zu unterstützen.

Ziele des Reflexes

  • Pure Python: Verwenden Sie eine Sprache für alles.
  • Einfacher Einstieg: Erstellen Sie Ihre Ideen ganz einfach, ohne dass Sie Erfahrung in der Webentwicklung benötigen.
  • Volle Flexibilität: Web-Apps sollten die Anpassbarkeit und Leistung herkömmlicher Web-Frameworks aufweisen.
  • Batterien im Lieferumfang enthalten: Behandeln Sie den gesamten Stack vom Frontend über das Backend bis zur Bereitstellung.

Lassen Sie uns nun näher darauf eingehen, wie wir Reflex entwickelt haben, um diese Ziele zu erreichen.

Die Reflexarchitektur

Full-Stack-Web-Apps bestehen aus einem Frontend und einem Backend. Das Frontend ist die Benutzeroberfläche und wird als Webseite bereitgestellt, die im Browser des Benutzers ausgeführt wird. Das Backend übernimmt die Logik- und Statusverwaltung (z. B. Datenbanken und APIs) und wird auf einem Server ausgeführt.

Bei der traditionellen Webentwicklung handelt es sich normalerweise um zwei separate Apps, die häufig in unterschiedlichen Frameworks oder Sprachen geschrieben sind. Sie können beispielsweise ein Flask-Backend mit einem React-Frontend kombinieren. Bei diesem Ansatz müssen Sie zwei separate Apps verwalten und am Ende viel Standardcode schreiben, um das Front-End und das Backend zu verbinden.

Wir möchten diesen Prozess in Reflex vereinfachen, indem wir sowohl das Frontend als auch das Backend in einer einzigen Codebasis definieren und gleichzeitig Python für alles verwenden. Entwickler sollten sich nur um die Logik ihrer App kümmern und nicht um die Implementierungsdetails auf niedriger Ebene.

Designing a Pure Python Web Framework

Frontend

Wir möchten, dass Reflex-Apps für den Endbenutzer wie eine herkömmliche Web-App aussehen und sich anfühlen, während sie für den Entwickler dennoch einfach zu erstellen und zu warten sind. Zu diesem Zweck haben wir auf ausgereiften und beliebten Webtechnologien aufgebaut.

Wenn Sie Ihre App per Reflex ausführen, kompiliert Reflex das Frontend zu einer einseitigen Next.js-App und stellt sie an einem Port (standardmäßig 3000) bereit, auf den Sie in Ihrem Browser zugreifen können.

Die Aufgabe des Frontends besteht darin, den Status der App wiederzugeben und Ereignisse an das Backend zu senden, wenn der Benutzer mit der Benutzeroberfläche interagiert. Im Frontend wird keine eigentliche Logik ausgeführt.

Komponenten

Reflex-Frontends werden aus Komponenten erstellt, die zu komplexen Benutzeroberflächen zusammengesetzt werden können. Anstatt eine Vorlagensprache zu verwenden, die HTML und Python mischt, verwenden wir einfach Python-Funktionen, um die Benutzeroberfläche zu definieren.

Unter der Haube werden Komponenten zu React-Komponenten kompiliert.

Viele unserer Kernkomponenten basieren auf Radix, einer beliebten React-Komponentenbibliothek. Wir haben auch viele andere Komponenten für Grafiken, Datentabellen und mehr.

Wir haben uns für React entschieden, weil es eine beliebte Bibliothek mit einem riesigen Ökosystem ist. Unser Ziel ist es nicht, das Web-Ökosystem neu zu erstellen, sondern es Python-Entwicklern zugänglich zu machen.

Auf diese Weise können unsere Benutzer auch ihre eigenen Komponenten mitbringen, wenn wir eine Komponente nicht haben, die sie benötigen. Benutzer können ihre eigenen React-Komponenten verpacken und sie dann veröffentlichen, damit andere sie verwenden können. Im Laufe der Zeit werden wir unser Drittanbieter-Komponenten-Ökosystem ausbauen, damit Benutzer Komponenten, die andere erstellt haben, leicht finden und verwenden können.

Styling

Wir wollten sicherstellen, dass Reflex-Apps sofort gut aussehen und Entwicklern dennoch die volle Kontrolle über das Erscheinungsbild ihrer App geben.

Wir verfügen über ein zentrales Designsystem, mit dem Sie in Ihrer gesamten App hochstufige Styling-Optionen wie den Dunkelmodus und die Akzentfarbe festlegen können, um ihr ein einheitliches Erscheinungsbild zu verleihen.

Darüber hinaus können Reflex-Komponenten mit der vollen Leistungsfähigkeit von CSS gestaltet werden. Wir nutzen die Emotion-Bibliothek, um „CSS-in-Python“-Styling zu ermöglichen, sodass Sie jede CSS-Requisite als Schlüsselwortargument an eine Komponente übergeben können. Dazu gehören reaktionsfähige Requisiten durch Übergabe einer Werteliste.

Backend

In Reflex wird nur das Frontend zu Javascript kompiliert und im Browser des Benutzers ausgeführt, während der gesamte Status und die gesamte Logik in Python verbleiben und auf dem Server ausgeführt werden. Wenn Sie Reflex ausführen, starten wir einen FastAPI-Server (standardmäßig auf Port 8000), mit dem sich das Frontend über einen Websocket verbindet.

Der gesamte Status und die gesamte Logik werden innerhalb einer State-Klasse definiert.

Der Zustand besteht aus Variablen und Ereignishandlern.

Vars sind alle Werte in Ihrer App, die sich im Laufe der Zeit ändern können. Sie werden als Klassenattribute Ihrer State-Klasse definiert und können ein beliebiger Python-Typ sein, der in JSON serialisiert werden kann.

Ereignishandler sind Methoden in Ihrer State-Klasse, die aufgerufen werden, wenn der Benutzer mit der Benutzeroberfläche interagiert. Sie sind die einzige Möglichkeit, die Variablen in Reflex zu ändern, und können als Reaktion auf Benutzeraktionen aufgerufen werden, z. B. das Klicken auf eine Schaltfläche oder das Eingeben in ein Textfeld.

Da Event-Handler im Backend ausgeführt werden, können Sie jede darin enthaltene Python-Bibliothek verwenden.

Designing a Pure Python Web Framework

Ereignisverarbeitung

Normalerweise muss man beim Schreiben von Web-Apps viel Boilerplate-Code schreiben, um das Front-End und das Backend zu verbinden. Mit Reflex müssen Sie sich darüber keine Gedanken machen – wir übernehmen für Sie die Kommunikation zwischen Frontend und Backend. Entwickler müssen lediglich ihre Event-Handler-Logik schreiben, und wenn die Variablen aktualisiert werden, wird die Benutzeroberfläche automatisch aktualisiert.

Ereignisauslöser

Der Benutzer kann auf viele Arten mit der Benutzeroberfläche interagieren, z. B. indem er auf eine Schaltfläche klickt, in ein Textfeld eingibt oder mit der Maus über ein Element fährt. In Reflex nennen wir diese Ereignisauslöser.

Ereigniswarteschlange

Im Frontend verwalten wir eine Ereigniswarteschlange aller ausstehenden Ereignisse. Ein Ereignis besteht aus drei Hauptdaten:

  • Client-Token: Jeder Client (Browser-Registerkarte) verfügt über ein eindeutiges Token, um ihn zu identifizieren. Dadurch weiß das Backend, welcher Status aktualisiert werden soll.
  • Ereignishandler: Der Ereignishandler, der im Status ausgeführt werden soll.
  • Argumente: Die Argumente, die an den Ereignishandler übergeben werden sollen.

Wenn ein Ereignis ausgelöst wird, wird es zur Warteschlange hinzugefügt.
Wir haben ein Verarbeitungsflag, um sicherzustellen, dass jeweils nur ein Ereignis verarbeitet wird. Dadurch wird sichergestellt, dass der Status immer konsistent ist und es keine Race Conditions gibt, bei denen zwei Event-Handler den Status gleichzeitig ändern. Es gibt Ausnahmen hiervon, wie zum Beispiel Hintergrundereignisse, die es Ihnen ermöglichen, Ereignisse im Hintergrund auszuführen, ohne die Benutzeroberfläche zu blockieren.

Sobald das Ereignis zur Verarbeitung bereit ist, wird es über eine WebSocket-Verbindung an das Backend gesendet.

Staatsmanager

Sobald das Ereignis empfangen wurde, wird es im Backend verarbeitet.

Reflex verwendet einen Statusmanager, der eine Zuordnung zwischen Client-Tokens und ihrem Status verwaltet. Standardmäßig ist der Statusmanager nur ein In-Memory-Wörterbuch, er kann jedoch erweitert werden, um eine Datenbank oder einen Cache zu verwenden. In der Produktion nutzen wir Redis als unseren State Manager.

Ereignisbehandlung

Sobald wir den Status des Benutzers haben, besteht der nächste Schritt darin, den Event-Handler mit den Argumenten auszuführen.

Statusaktualisierungen

Jedes Mal, wenn ein Event-Handler zurückkehrt (oder nachgibt), speichern wir den Status im Statusmanager und senden die Statusaktualisierungen an das Frontend, um die Benutzeroberfläche zu aktualisieren.

Um die Leistung aufrechtzuerhalten, während Ihr Status wächst, verfolgt Reflex intern die Variablen, die während des Ereignishandlers aktualisiert wurden (schmutzige Variablen).
Wenn der Event-Handler mit der Verarbeitung fertig ist, finden wir alle fehlerhaften Variablen und erstellen eine Statusaktualisierung, die wir an das Frontend senden.

Wir speichern den neuen Status in unserem Statusmanager und senden dann die Statusaktualisierung an das Frontend.
Das Frontend aktualisiert dann die Benutzeroberfläche, um den neuen Status widerzuspiegeln.

Abschluss

Ich hoffe, dass dies einen guten Überblick darüber gibt, wie Reflex unter der Haube funktioniert. Wir werden weitere Beiträge veröffentlichen, in denen wir berichten, wie wir Reflex durch Funktionen wie State Sharding und Compiler-Optimierungen skalierbar und leistungsfähig gemacht haben.

Das obige ist der detaillierte Inhalt vonEntwerfen eines reinen Python-Web-Frameworks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn