Flask - Funktionsweise des route() Decorator

Django, Flask, Bottle, WSGI, CGI…
Antworten
worstplayereuw
User
Beiträge: 2
Registriert: Samstag 6. Februar 2021, 23:03

Hallo!
Habe vor kurzem erst mit Flask angefangen und mir persönlich ist es sehr wichtig was hinter den Kulissen vorgeht.
Mit folgendem Code ist es möglich ein "Hello World" der Webseite anzeigen zu lassen:

Code: Alles auswählen

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

if __name__ == "__main__":
    app.run(port=1337, debug=True)
Gut. Nun war es mir wichtig zu wissen, wie der Decorator route funktioniert.
Habe also mal einen Blick in die Definition von route reingeschaut und bin hierauf gestoßen (die Kommentare im Code lasse ich mal weg):

Code: Alles auswählen

  
  def route(self, rule, **options):
     
        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator
Was mich jetzt total verwirrt ist, dass gar nicht die Funktion route als Argument die Funktion (in meinem Fall index()) nimmt,
sondern die Wrapperfunktion, also decorator(f). Habe Decorator halt so beigebracht bekommen, dass dem Decorator (hier route)
die Funktion, die dekoriert werden soll, als Parameter übergeben werden soll und nicht der Wrapperfunktion. Die Wrapperfunktion soll ja,
meines Wissens nach, die Funktion die dem Decorator übergeben wurde erweitern...

Von daher würde ich mich freuen, wenn man mir erklären könnte, was genau in dem Prozess passiert bzw. welche Funktionen/Parameter
aufgerufen und/oder an wen übergeben werden.

Mit freundlichen Grüßen
Markus
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

route ist auch kein Dekorator, sondern der Rückgabewert des Funktionsaufrufs `app.route("/")` ist der Dekorator.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

route generiert einen decorator. Ein klassischer “Trick” um die benötigten Parameter an route zu erhalten & mit denen dann arbeiten zu können im eigentlichen decorator.
worstplayereuw
User
Beiträge: 2
Registriert: Samstag 6. Februar 2021, 23:03

Ok, aber ich verstehe nicht ganz wie und woher die Funktion decorator(f) meine Index-Funktion herbekommt.
Mit @app.route("/") würde halt die Route-Funktion aufgerufen werden und ein "/" übergeben. Jetzt wird halt
der Dekorator "decorator" zurückgegeben. Ab hier weiß ich nicht mehr weiter, wie es genau weitergeht, weil
nirgendswo die Decoratorfunktion aufgerufen und meine Index-Funktion übergeben wird.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@worstplayereuw: Doch wird sie. Die Dekoratorsyntax ist ja nur syntaktischer Zucker für folgendes:

Code: Alles auswählen

@some_expression
def function():
   ...

# ist äquivalent zu

def function():
   ...

function = (some_expression)(function)
Hier musst Du `some_expression` durch den Ausdruck ersetzen den Du bei Flask verwendest:

Code: Alles auswählen

@route("/")
def function():
   ...

# ist äquivalent zu

def function():
   ...

function = route("/")(function)
Dadurch das der Ausdruck hinter dem @ ein Aufruf ist, fällt nicht der Aufruf durch die @-Syntax weg. `some_expression` kann ein beliebig komplizierter Ausdruck sein. Da kann auch das hier stehen:

Code: Alles auswählen

@MAPPING["key"] + frobnicate(4711) << (42, 23)
def function():
   ...

# ist äquivalent zu

def function():
   ...

function = (MAPPING["key"] + frobnicate(4711) << (42, 23))(function)
Das einzige was hier wichtig ist, ist das der Ausdruck als Ergebnis etwas hat, was aufrufbar ist und ein Argument erwartet — die zu dekorierende Funktion. Das heisst in diesem schrägen Beispiel müssen die beteiligten Objekte von den Zwischenergebnissen ``+`` beziehungsweise ``<<`` entsprechend überladen haben, so dass das der Fall ist.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten