[Python] Lesen Sie den Quellcode von Flasche Teil 2

Dieser Artikel ist eine Fortsetzung von Letztes Mal, aber Sie sollten ihn problemlos alleine lesen können. Nun, es ist ein Artikel für meine eigene Organisation ...

Honmarus Flaschenklasse

Schließlich die "Flaschen" -Klasse des Burgturms. Zuallererst vom letzten Mal mit der Methode __call__.

bottle.py



class Bottle(object):

    def __call__(self, environ, start_response):
        """ Each instance of :class:'Bottle' is a WSGI application. """
        return self.wsgi(environ, start_response)

    def wsgi(self, environ, start_response):
        """ The bottle WSGI-interface. """
        try:
            out = self._cast(self._handle(environ))
            # rfc2616 section 4.3
            if response._status_code in (100, 101, 204, 304) or environ['REQUEST_METHOD'] == 'HEAD':
                if hasattr(out, 'close'): out.close()
                out = []
            start_response(response._status_line, response.headerlist)
            return out

Mit anderen Worten, der Nachrichtentextteil der Antwort wird aus "self._cast (self._handle (environ))" generiert. Da "self.cast ()" ein Prozess zum Codieren von Daten in ein für eine HTTP-Nachricht geeignetes Format ist, wird der Antwortinhalt tatsächlich von "self._handle (environ)" erstellt.

Das ist etwas lang. Also werde ich versuchen, es bis auf den Ausnahmeblock zu aktualisieren.

bottle.py



#: A thread-safe instance of :class:`LocalResponse`. It is used to change the
#: HTTP response for the *current* request.
response = LocalResponse()

class Bottle(object):

    def _handle(self, environ):
        path = environ['bottle.raw_path'] = environ['PATH_INFO']
        if py3k:
            environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')

        environ['bottle.app'] = self
        request.bind(environ)
        response.bind()

        try:
            while True: # Remove in 0.14 together with RouteReset
                out = None
                try:
                    self.trigger_hook('before_request')
                    route, args = self.router.match(environ)
                    environ['route.handle'] = route
                    environ['bottle.route'] = route
                    environ['route.url_args'] = args
                    out = route.call(**args)
                    break
                
                finally:
                    if isinstance(out, HTTPResponse):
                        out.apply(response)
                    try:
                        self.trigger_hook('after_request')

        return out

Response = LocalResponse () erschien plötzlich hier, aber die übergeordnete Klasse BaseResponse der LocalResponse-Klasse ist unten definiert.

bottle.py


class BaseResponse(object):
    """ Storage class for a response body as well as headers and cookies.

        This class does support dict-like case-insensitive item-access to
        headers, but is NOT a dict. Most notably, iterating over a response
        yields parts of the body and not the headers. #Die folgenden Kommentare werden weggelassen
    """

    default_status = 200
    default_content_type = 'text/html; charset=UTF-8'

    def __init__(self, body='', status=None, headers=None, **more_headers):
        self._cookies = None
        self._headers = {}
        self.body = body

Es scheint Informationen wie Cookies, Header und Textkörper zu enthalten. Ich werde vorerst nicht weiter jagen.

Nun ist "Bottle () ._ handler ()"

route, args = self.router.match(environ)
out = route.call(**args)
return out

Dieser Teil ist der Schlüssel, und es scheint, dass der Routing-Prozess hier ausgeführt wird. Hier bedeutet "self.router" "Router ()" (definiert in "Bottle .__ init__"). Schauen wir uns also diese Klasse an.

bottle.py



class Router(object):
    """ A Router is an ordered collection of route->target pairs. It is used to
        efficiently match WSGI requests against a number of routes and return
        the first target that satisfies the request. The target may be anything,
        usually a string, ID or callable object. A route consists of a path-rule
        and a HTTP method.

        The path-rule is either a static path (e.g. `/contact`) or a dynamic
        path that contains wildcards (e.g. `/wiki/<page>`). The wildcard syntax
        and details on the matching order are described in docs:`routing`.
    """

    def __init__(self, strict=False):
        self.rules = []  # All rules in order
        self._groups = {}  # index of regexes to find them in dyna_routes
        self.builder = {}  # Data structure for the url builder
        self.static = {}  # Search structure for static routes
        self.dyna_routes = {}
        self.dyna_regexes = {}  # Search structure for dynamic routes
        #: If true, static routes are no longer checked first.
        self.strict_order = strict
        self.filters = {
            're': lambda conf: (_re_flatten(conf or self.default_pattern),
                                None, None),
            'int': lambda conf: (r'-?\d+', int, lambda x: str(int(x))),
            'float': lambda conf: (r'-?[\d.]+', float, lambda x: str(float(x))),
            'path': lambda conf: (r'.+?', None, None)
        }

    def match(self, environ):
        """ Return a (target, url_args) tuple or raise HTTPError(400/404/405). """
        verb = environ['REQUEST_METHOD'].upper()
        path = environ['PATH_INFO'] or '/'

        if verb == 'HEAD':
            methods = ['PROXY', verb, 'GET', 'ANY']
        else:
            methods = ['PROXY', verb, 'ANY']

        for method in methods:
            if method in self.static and path in self.static[method]:
                target, getargs = self.static[method][path]
                return target, getargs(path) if getargs else {}
            elif method in self.dyna_regexes:
                for combined, rules in self.dyna_regexes[method]:
                    match = combined(path)
                    if match:
                        target, getargs = rules[match.lastindex - 1]
                        return target, getargs(path) if getargs else {}

Es ist ein wenig chaotisch hier und es ist schwer zu verstehen, was das "Ziel" von "Rückgabeziel, get args (path)" ist, aber wie Sie sehen können, wenn Sie sich "route" ansehen, ist args = self.router.match (environ) " , Die Route-Instanz wird zurückgegeben, nicht wahr?

Mit anderen Worten, bevor Sie es wissen, wird "Route ()" als "self.static [method] [path]" registriert.

Bevor Sie es wissen! ?? </ b>

Wenn Sie sich die Quellen unten ansehen, sehen Sie nach und nach das große Ganze!

bottle.py



class Bottle(object):

    def route(self,
              path=None,
              method='GET',
              callback=None,
              name=None,
              apply=None,
              skip=None, **config):
        """ A decorator to bind a function to a request URL. Example::

                @app.route('/hello/<name>')
                def hello(name):
                    return 'Hello %s' % name

            The ``<name>`` part is a wildcard. See :class:`Router` for syntax
            details.
        """
        if callable(path): path, callback = None, path
        plugins = makelist(apply)
        skiplist = makelist(skip)

        def decorator(callback):
            if isinstance(callback, basestring): callback = load(callback)
            for rule in makelist(path) or yieldroutes(callback):
                for verb in makelist(method):
                    verb = verb.upper()
                    route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
                    self.add_route(route)
            return callback

        return decorator(callback) if callback else decorator


    def add_route(self, route):
        """ Add a route object, but do not change the :data:`Route.app`
            attribute."""
        self.routes.append(route)
        self.router.add(route.rule, route.method, route, name=route.name)
        if DEBUG: route.prepare()

Also wir


@app.route('/hello/<name>')
    def hello(name):
        return 'Hello %s' % name

Durch Anbringen eines Dekorateurs, wenn eine Anfrage fliegt


route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)

Und Sie haben der Instanz "Router" Informationen über die Instanz "Route" gegeben.

Irgendwie wurde mein Kopf wütend ...

Antwortdaten

Was ich daraus gelernt habe

route, args = self.router.match(environ)
out = route.call(**args)
return out  #Antwortdaten sind enthalten!

Die "Route" in ist eine Instanz der "Route" (obwohl dies offensichtlich erscheint), und die "Route (). Call ()" enthält die gewünschten Antwortdaten!

Wenn Sie sich also die Definition der Klasse "Route" ansehen

bottle.py



class Route(object):
    """ This class wraps a route callback along with route specific metadata and
        configuration and applies Plugins on demand. It is also responsible for
        turing an URL path rule into a regular expression usable by the Router.
    """

    def __init__(self, app, rule, method, callback,
                 name=None,
                 plugins=None,
                 skiplist=None, **config):
        #: The application this route is installed to.
        self.app = app
        self.callback = callback
        #: A list of route-specific plugins (see :meth:`Bottle.route`).
        self.plugins = plugins or []

    @cached_property
    def call(self):
        """ The route callback with all plugins applied. This property is
            created on demand and then cached to speed up subsequent requests."""
        return self._make_callback()

    def _make_callback(self):
        callback = self.callback
        for plugin in self.all_plugins():
            try:
                if hasattr(plugin, 'apply'):
                    callback = plugin.apply(callback, self)
                else:
                    callback = plugin(callback)
            except RouteReset:  # Try again with changed configuration.
                return self._make_callback()
            if not callback is self.callback:
                update_wrapper(callback, self.callback)
        return callback

Mit anderen Worten, das Plug-In ist eingeklemmt, und der wichtige Teil ist "self.callback", aber dieser befindet sich in erster Linie in "Bottle.route"

bottle.py



        def decorator(callback):
            if isinstance(callback, basestring): callback = load(callback)
            for rule in makelist(path) or yieldroutes(callback):
                for verb in makelist(method):
                    verb = verb.upper()
                    route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
                    self.add_route(route)
            return callback

        return decorator(callback) if callback else decorator

Sie haben gerade den Rückruf bestanden, der eingegangen ist. das ist

@app.route('/hello/<name>')
    def hello(name):
        return 'Hello %s' % name

Es entspricht der "Hallo" -Funktion in, was ebenfalls ganz natürlich ist, aber die Antwortdaten werden gemäß der hier definierten Funktion generiert.

Chan-Chan.

jemand hilft

So habe ich endlich das ganze Bild bekommen (obwohl ich die Teile der Protokollierung und Fehlerbehandlung ignoriert habe).

Aber die Frage ist

from bottle import route

Ich habe keine Ahnung, warum der "Route" -Dekorator geladen ist. Es fühlt sich so an, als ob die in der Klasse "Route" definierte Dekorationsfunktion in der Umgebung unter dem Namen "Route" registriert ist.

Wenn jemand versteht, lass es mich wissen ... weinen

Recommended Posts

[Python] Lesen Sie den Quellcode von Flasche Teil 2
[Python] Lesen Sie den Quellcode von Flasche Teil 1
[Python] Lesen Sie den Flask-Quellcode
[Python3] Schreiben Sie das Codeobjekt der Funktion neu
[Python] Ruft den Zeichencode der Datei ab
Warum die Python-Implementierung von ISUCON 5 Bottle verwendet
der Zen von Python
Code zum Überprüfen des Betriebs von Python Matplot lib
Konvertieren Sie den Zeichencode der Datei mit Python3
[Python + OpenCV] Malen Sie den transparenten Teil des Bildes weiß
Vorlage des Python-Skripts zum Lesen des Inhalts der Datei
Erläuterung des Konzepts der Regressionsanalyse mit Python Teil 2
Schneiden Sie einen Teil der Zeichenfolge mit einem Python-Slice aus
Lassen Sie uns die Grundlagen des Python-Codes von TensorFlow aufschlüsseln
Holen Sie sich den Rückkehrcode eines Python-Skripts von bat
Erläuterung des Konzepts der Regressionsanalyse mit Python Teil 1
Auf dem Weg zum Ruhestand von Python2
Erläutern Sie den Code von Tensorflow_in_ROS
2.x, 3.x Serienzeichencode von Python
Über die Funktionen von Python
Quellinstallation und Installation von Python
Python x GIS-Grundlagen (1)
Ich habe die Python-Quelle heruntergeladen
Die Kraft der Pandas: Python
Sakura Die Geschichte, wie die Python-Flasche im Internet funktioniert hat
Der Prozess, Python-Code objektorientiert zu machen und zu verbessern
Holen Sie sich die Quelle der Seite unbegrenzt mit Python zu laden.
Python x GIS-Grundlagen (3)
Die Geschichte von Python und die Geschichte von NaN
[Python] Der Stolperstein des Imports
Erster Python 3 ~ Der Beginn der Wiederholung ~
Existenz aus Sicht von Python
pyenv-change die Python-Version von virtualenv
Lassen Sie Python die Befehlsausgabe lesen
[Python] Die potenzielle Feldplanung von Python Robotics verstehen
Überprüfung der Grundlagen von Python (FizzBuzz)
Grundlagen von Python x GIS (Teil 2)
Informationen zur Grundlagenliste der Python-Grundlagen
Lernen Sie die Grundlagen von Python ① Grundlegende Anfänger
Anzahl Quellcodezeilen (SLOC)
Wrap (Teil der) AtCoder Library in Cython zur Verwendung in Python
Folgen Sie dem QAOA-Fluss (VQE) auf der Quellcode-Ebene von Blueqat
Messen Sie die Testabdeckung von Push-Python-Code auf GitHub.
[PEP8] Übernehmen Sie den Python-Quellcode und schreiben Sie ihn ordentlich
Erste Python ② Versuchen Sie, Code zu schreiben, während Sie die Funktionen von Python untersuchen
Lesen Sie die Standardausgabe eines Unterprozesses zeilenweise in Python
Ich habe den Code geschrieben, um den Brainf * ck-Code in Python zu schreiben
Fassen wir den Grad der Kopplung zwischen Modulen mit Python-Code zusammen
Installation von Visual Studio Code und Installation von Python
Zeigen Sie den Implementierungsquellcode in iPython an
Ändern Sie die Länge der Python-CSV-Zeichenfolgen
Überprüfen Sie das Verhalten des Zerstörers in Python
[Python3] Verstehe die Grundlagen von Beautiful Soup
So schneiden Sie den unteren rechten Teil des Bildes mit Python OpenCV
Übergeben Sie den Pfad des importierten Python-Moduls
Implementieren Sie einen Teil des Prozesses in C ++
Notizen vom Anfang von Python 1 lernen