Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"

Das Buch wurde aktualisiert

Kapitel "Anforderungs- / Antwort- / Ansichtsklasse erstellen, um die Sichtbarkeit zu verbessern" Das wurde aktualisiert.

Wenn Sie mehr lesen möchten, "mögen" oder "folgen Sie mir" in Buch ;-)


Das Folgende ist ein Auszug aus dem Inhalt des Buches.


Refactor

Es gibt jetzt drei Endpunkte, die dynamische Antworten generieren, und workerthread.py liegt jetzt nahe bei 200 Zeilen.

Selbst zu diesem Zeitpunkt mache ich viele verschiedene Dinge mit einer Datei, sodass selbst 200 Zeilen zu einem überfüllten Modul mit sehr schlechter Sicht geworden sind.

Wenn Sie diese Webanwendung weiterentwickeln, werden Sie außerdem immer mehr Endpunkte haben. Es ist offensichtlich, dass eine Wartung nicht möglich ist, wenn Sie sie jedes Mal zu "workerthread.py" hinzufügen. Man kann sagen, dass es notwendig wurde, die Sichtbarkeit von workerthread.py durch Trennen von Verantwortlichkeiten und Teilen von Dateien zu verbessern.

Mit anderen Worten, es ist an der Zeit, dass die Saison für das Refactoring gekommen ist.

In diesem Kapitel werden wir "Verarbeitung, die dynamisch einen Antworttext für jeden Endpunkt generiert" für ein externes Modul ausschneiden.

SCHRITT 1: Einfach als Funktion ausschneiden

Lassen Sie uns zunächst einfach den HTML-Generierungsprozess für jeden Endpunkt in ein anderes Modul ausschneiden.

Der Name des auszuschneidenden Moduls lautet "Ansichten". Dies liegt daran, dass es sich um ein Modul handelt, dessen Aufgabe es ist, unabhängig von der HTTP-Situation, wie z. B. der Verbindung oder dem Parsen des Headers, nur den Ansichtsteil (= Anforderungshauptteil) zu generieren.

Quellcode

study/workerthread.py https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter16/workerthread.py#L50-L59

study/views.py https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter16/views.py

Kommentar

study/workerthread.py

Zeilen 57-66

            if path == "/now":
                response_body, content_type, response_line = views.now()

            elif path == "/show_request":
                response_body, content_type, response_line = views.show_request(
                    method, path, http_version, request_header, request_body
                )

            elif path == "/parameters":
                response_body, content_type, response_line = views.parameters(method, request_body)

Bis zum letzten Mal schrieb ich, dass der Prozess des Generierens von HTML für jeden Pfad schwierig war, aber zuerst entschied ich mich, diesen Teil auf die Funktion des Moduls "Ansichten" auszuschneiden.

dadurch,

--workerthread.py empfängt die HTTP-Anforderung, analysiert sie, ruft den Antwortinhalt von der Funktion des views-Moduls gemäß dem Pfad ab, erstellt die HTTP-Antwort und gibt sie an den Client zurück. --views.py hat eine Funktion für jeden Pfad, empfängt den Inhalt der Anforderung und gibt den Inhalt der dynamisch generierten Antwort zurück.

Die Aufgabe, "den Inhalt der Antwort dynamisch gemäß dem Pfad zu generieren", wurde in "Ansichten" herausgeschnitten.

study/views.py

import textwrap
import urllib.parse
from datetime import datetime
from pprint import pformat
from typing import Tuple, Optional


def now() -> Tuple[bytes, Optional[str], str]:
    """
Generieren Sie HTML, um die aktuelle Uhrzeit anzuzeigen
    """
    html = f"""\
        <html>
        <body>
            <h1>Now: {datetime.now()}</h1>
        </body>
        </html>
    """
    response_body = textwrap.dedent(html).encode()

    # Content-Geben Sie den Typ an
    content_type = "text/html; charset=UTF-8"

    #Generieren Sie eine Antwortzeile
    response_line = "HTTP/1.1 200 OK\r\n"

    return response_body, content_type, response_line


def show_request(
    method: str,
    path: str,
    http_version: str,
    request_header: dict,
    request_body: bytes,
) -> Tuple[bytes, Optional[str], str]:
    """
Generieren Sie HTML, um den Inhalt der HTTP-Anforderung anzuzeigen
    """
    html = f"""\
        <html>
        <body>
            <h1>Request Line:</h1>
            <p>
                {method} {path} {http_version}
            </p>
            <h1>Headers:</h1>
            <pre>{pformat(request_header)}</pre>
            <h1>Body:</h1>
            <pre>{request_body.decode("utf-8", "ignore")}</pre>

        </body>
        </html>
    """
    response_body = textwrap.dedent(html).encode()

    # Content-Geben Sie den Typ an
    content_type = "text/html; charset=UTF-8"

    #Generieren Sie eine Antwortzeile
    response_line = "HTTP/1.1 200 OK\r\n"

    return response_body, content_type, response_line


def parameters(
    method: str,
    request_body: bytes,
) -> Tuple[bytes, Optional[str], str]:
    """
HTML anzeigen mit POST-Parametern
    """

    #Gibt 405 für GET-Anforderungen zurück
    if method == "GET":
        response_body = b"<html><body><h1>405 Method Not Allowed</h1></body></html>"
        content_type = "text/html; charset=UTF-8"
        response_line = "HTTP/1.1 405 Method Not Allowed\r\n"

    elif method == "POST":
        post_params = urllib.parse.parse_qs(request_body.decode())
        html = f"""\
            <html>
            <body>
                <h1>Parameters:</h1>
                <pre>{pformat(post_params)}</pre>                        
            </body>
            </html>
        """
        response_body = textwrap.dedent(html).encode()

        # Content-Geben Sie den Typ an
        content_type = "text/html; charset=UTF-8"

        #Generieren Sie eine Antwortzeile
        response_line = "HTTP/1.1 200 OK\r\n"

    return response_body, content_type, response_line

Dies ist auch nicht besonders schwierig. Ich habe gerade den Prozess der dynamischen Generierung der Antwort eingeführt, die ursprünglich in "workerthread.py" geschrieben wurde.


Es ist gut, die Ansichtsfunktion auszuschneiden, aber wie es jetzt ist, ist die Anzahl der Argumente für jede Funktion unterschiedlich. "Das Pseudonym, das diesen Pfad verarbeitet, benötigt die Argumente von diesem und jenem, und die Funktion, die diesen Pfad verarbeitet, benötigt die Argumente von diesem und jenem und jenem ..." Und so weiter muss der Anrufer die Details des Anrufers kennen.

In der Welt der Programmierung ist bekannt, dass der Quellcode einfach wird, wenn ein Modul erstellt wird, so dass die Details des anderen Moduls nicht so weit wie möglich bekannt sind.

Lassen Sie uns im nächsten SCHRITT etwas mehr mit dem Refactoring fortfahren und dies erkennen.

SCHRITT 2: Vereinheitlichen Sie die Benutzeroberfläche der Ansichtsfunktion

Jetzt muss die WorkerThread-Klasse die Details der Ansichtsfunktion kennen, da sie nicht aufgerufen werden kann, ohne zu wissen, welche und wie viele Argumente sie für jede Funktion benötigt.

Eine einfache Möglichkeit, diese Situation zu beseitigen, ist ** "Ich weiß nicht, welchen Parameter jede Funktion verwendet, aber ich werde trotzdem alles übergeben" **.

Quellcode

Schauen wir uns den Quellcode an.

study/workerthread.py https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter16-2/workerthread.py

study/views.py https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter16-2/views.py

Kommentar

study/views.py Beginnen wir mit views.py

Zeilen 8-14, 66-72

def now(
    method: str,
    path: str,
    http_version: str,
    request_header: dict,
    request_body: bytes,
) -> Tuple[bytes, Optional[str], str]:
def parameters(
    method: str,
    path: str,
    http_version: str,
    request_header: dict,
    request_body: bytes,
) -> Tuple[bytes, Optional[str], str]:

Die Argumente sind in allen Ansichtsfunktionen vereinheitlicht, sodass alle Anforderungsinformationen empfangen werden können. Diese Argumente werden in der Funktion nicht verwendet, aber wenn der Aufrufer sie zur Verfügung stellt, muss er nicht darüber nachdenken, "was benötigt wird und was nicht".

study/workerthread.py Als nächstes kommt die Seite, die die Ansichtsfunktion aufruft.

Zeilen 29-34

    #Korrespondenz zwischen Pfad- und Ansichtsfunktionen
    URL_VIEW = {
        "/now": views.now,
        "/show_request": views.show_request,
        "/parameters": views.parameters,
    }

Die Entsprechung zwischen den Pfad- und Ansichtsfunktionen wird als Konstante definiert. Es ist ein ** Wörterbuch mit Pfad als Schlüssel und ** Ansichtsfunktion, die Pfad als Wert entspricht.

Spalte: Python-Funktionen sind primäre Objekte

Abhängig von der Sprache können Sie überrascht sein, "eine" Funktion "als Wörterbuchwert (oder assoziatives Array) festzulegen" oder "einer Variablen eine" Funktion "zuzuweisen", wie oben beschrieben.

Aber in Python ist dies eine legitime Behandlung.

Objekte, die als Werte behandelt werden können, z. B. die Zuweisung zu Variablen und die Übergabe an Operationen und Funktionen (als Argumente und Rückgabewerte), werden als ** erstklassige Objekte ** bezeichnet. In Python ** sind alle Objekte primäre Objekte ** und Funktionen sind keine Ausnahme.

Daher ist es möglich, einer Variablen eine Funktion zuzuweisen oder eine Funktion zu erstellen, die eine Funktion empfängt und eine Funktion zurückgibt.

Letzteres ist als "Metaprogrammierung" bekannt und jeder Interessierte sollte es ausprobieren.

Zeile 64-69

            #Wenn es eine Ansichtsfunktion gibt, die dem Pfad entspricht, rufen Sie die Funktion ab und rufen Sie sie auf, um eine Antwort zu generieren
            if path in self.URL_VIEW:
                view = self.URL_VIEW[path]
                response_body, content_type, response_line = view(
                    method, path, http_version, request_header, request_body
                )

path in self.URL_VIEW prüft, ob der Schlüssel im Wörterbuch self.URL_VIEW`` path enthält. Mit anderen Worten, wir prüfen, ob die dem Pfad entsprechende Ansichtsfunktion registriert ist.

Wenn es registriert wurde, wird der Wert des Wörterbuchs, das diesem Schlüssel entspricht, erfasst und der Variablen "Ansicht" zugewiesen. Das heißt, der Variablen view wird die ** Ansichtsfunktion ** zugewiesen (anstelle des Rückgabewerts beim Aufrufen der Ansichtsfunktion).

In der letzten Zeile wird view (~~) verwendet, um die der Variablen view zugewiesene Funktion aufzurufen und den Rückgabewert abzurufen.


Es ist erwähnenswert, dass ** alle Ansichtsfunktionen jetzt dieselben Argumente akzeptieren (method, path, http_version, request_header, request_body), wodurch die Ansichtsfunktion abstrahiert wird. ** ** **

Bisher waren die Argumente für jede Funktion unterschiedlich. Selbst wenn Sie "Aufruf der Ansichtsfunktion" sagten, konnten Sie sie nur dann korrekt aufrufen, wenn Sie wussten, "welche Art von Funktion die Funktion ist". Durch Vereinheitlichen der Argumente (= Vereinheitlichen der Schnittstelle) ** "Ich weiß nicht, was die Funktion ist, aber ich kann sie trotzdem aufrufen" **.

Dadurch entfällt die Notwendigkeit einer Verzweigung nach Pfad (oder Funktion) innerhalb von "Workerthread".

Spalte: Abstraktion

Auf diese Weise wird "es ist nicht notwendig, mit konkreten Dingen umzugehen, indem nur ein Teil der gemeinsamen Eigenschaften aus konkreten Dingen extrahiert wird" als "Abstraktion" bezeichnet. Es ist eine sehr wichtige Technik in der Programmierung.

In diesem Fall durch Vereinheitlichen der Schnittstelle von konkreten Funktionen wie now () show_rewuest () parameters "Nimmt fünf Argumente" Methode, Pfad, http_version, request_header, request_body "und gibt zwei Werte" response_body, response_line "zurück." Durch Extrahieren (= Abstrahieren) nur der Eigenschaft, des Aufrufers "Ich weiß nicht, wie viele Funktionen es sind, aber ich nenne es mit 5 Argumenten." Dies bedeutet, dass es so gehandhabt werden kann.

Oder Sie könnten "einheitliche Schnittstelle für die Abstraktion" sagen.

SCHRITT 3: Vereinfachen Sie die Oberfläche der Ansichtsfunktion

Es ist gut, dass die Ansichtsfunktion eine gemeinsame Oberfläche hat und der Aufrufer eine bessere Ansicht hat, aber es gibt viele fünf Argumente.

Die Tatsache, dass eine HTTP-Anfrage viele Informationen enthält, ist unvermeidlich, aber es ist umständlich, sie in separaten Variablen zu verteilen und zu speichern.

Erstellen wir also eine Klasse, die die HTTP-Anforderung ausdrückt, und fügen die Informationen dort zusammen.

Dies vereinfacht auch die Oberfläche der Ansichtsfunktion.


Weiter mit Buch!

Kapitel "Anforderungs- / Antwort- / Ansichtsklasse erstellen, um die Sichtbarkeit zu verbessern"

Recommended Posts

Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
Aktualisiert "Einführung in Python Web Application Homebrew für Webingenieure im 3. Jahr, die langsam sind"
[Einführung in die Udemy Python3 + -Anwendung] 43. for else-Anweisung
Einführung in Python For, While
[Einführung in die Udemy Python3 + -Anwendung] 42. für Anweisung, break-Anweisung und continue-Anweisung
[Einführung in die Udemy Python3 + -Anwendung] 58. Lambda
[Einführung in die Udemy Python3 + -Anwendung] 31. Kommentar
[Einführung in die Udemy Python3 + -Anwendung] 57. Decorator
[Einführung in die Udemy Python3 + -Anwendung] 56. Abschluss
[Einführung in die Udemy Python3 + -Anwendung] 59. Generator
[Einführung in die Udemy Python3 + -Anwendung] Zusammenfassung
Erste Schritte mit Python für Nicht-Ingenieure
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (5) [Einführung in den DB-Betrieb mit Django-Shell]
[Einführung in die Udemy Python3 + -Anwendung] 18. Listenmethode
[Einführung in die Udemy Python3 + -Anwendung] 63. Notation zur Einbeziehung des Generators
[Einführung in die Udemy Python3 + -Anwendung] 28. Kollektiver Typ
[Einführung in die Udemy Python3 + -Anwendung] 33. if-Anweisung
[Einführung in die Udemy Python3 + -Anwendung] 13. Zeichenmethode
[Einführung in die Udemy Python3 + -Anwendung] 55. In-Function-Funktionen
[Einführung in die Udemy Python3 + -Anwendung] 48. Funktionsdefinition
[Einführung in die Udemy Python3 + -Anwendung] 10. Numerischer Wert
[Einführung in die Udemy Python3 + -Anwendung] 21. Taple-Typ
[Einführung in die Udemy Python3 + -Anwendung] 45. Aufzählungsfunktion
[Einführung in die Udemy Python3 + -Anwendung] 41. Eingabefunktion
[Einführung in die Udemy Python3 + -Anwendung] 17. Listenoperation
[Einführung in die Udemy Python3 + -Anwendung] 65. Ausnahmebehandlung
[Einführung in die Udemy Python3 + -Anwendung] 11. Zeichenkette
[Einführung in die Udemy Python3 + -Anwendung] 44. Bereichsfunktion
[Einführung in die Udemy Python3 + -Anwendung] 46. Zip-Funktion
[Einführung in die Udemy Python3 + -Anwendung] 24. Wörterbuchtyp
[Python] Webanwendungsdesign für maschinelles Lernen
Eine Einführung in Python für maschinelles Lernen
[Einführung in die Udemy Python3 + -Anwendung] 8. Variablendeklaration
[Einführung in die Udemy Python3 + -Anwendung] 29. Methode festlegen
[Einführung in die Udemy Python3 + -Anwendung] 16. Listentyp
[Einführung in die Udemy Python3 + -Anwendung] 61. Wörterbucheinschlussnotation
[Einführung in die Udemy Python3 + -Anwendung] 22. Auspacken der Taples
Eine Einführung in Python für C-Sprachprogrammierer
[Einführung in die Udemy Python3 + -Anwendung] 47. Verarbeiten Sie das Wörterbuch mit einer for-Anweisung
Lassen Sie uns die kostenlose "Einführung in Python für maschinelles Lernen" bis zum 27. April online stellen
Eine Einführung in selbst erstellte Python-Webanwendungen für einen trägen Webingenieur im dritten Jahr
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (4) [Einführung in Routing-Einstellungen und MTV-Entwurfsmuster]
Auf Python 2.7.9 aktualisiert
[Einführung in die Udemy Python3 + -Anwendung] 26. Kopie des Wörterbuchs
[Einführung in die Udemy Python3 + -Anwendung] 23. Verwendung von Tapuru
[Einführung in die Udemy Python3 + -Anwendung] 60. Listeneinschlussnotation
[Einführung in die Udemy Python3 + -Anwendung] 19. Kopie der Liste
[Einführung in die Udemy Python3 + -Anwendung] 38. Bei der Beurteilung von None
Einführung in Tornado (1): Python Web Framework mit Tornado gestartet
[Einführung in die Udemy Python3 + -Anwendung] 40. while else-Anweisung
[Einführung in die Udemy Python3 + -Anwendung] 62. Legen Sie die Einschlussnotation fest
Schritte zum Entwickeln einer Webanwendung in Python
[Einführung in die Udemy Python3 + -Anwendung] 64. Namespace und Gültigkeitsbereich
[Einführung in Python3 Tag 20] Kapitel 9 Enträtseln des Webs (9.1-9.4)
[Einführung in Udemy Python3 + Application] 67. Befehlszeilenargumente
[Einführung in die Udemy Python3 + -Anwendung] 9. Drucken Sie zunächst mit print
Einführung in die Programmierung (Python) TA Tendenz für Anfänger