天天看點

Twisted微架構Klein源碼閱讀(一)

from klein import run, route

@route('/')
def home(request):
    return 'Hello, world!'

run("localhost", 8080)
           

首先進入其Klein.route

#route是Kelin類下的一個方法
route = _globalKleinApp.route
_globalKleinApp = Klein()
           
def route(self, url, *args, **kwargs):
        """
        Add a new handler for C{url} passing C{args} and C{kwargs} directly to
        C{werkzeug.routing.Rule}.  The handler function will be passed at least
        one argument an L{twisted.web.server.Request} and any keyword arguments
        taken from the C{url} pattern.

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

        @param url: A werkzeug URL pattern given to C{werkzeug.routing.Rule}.
        @type url: str

        @param branch: A bool indiciated if a branch endpoint should
            be added that allows all child path segments that don't
            match some other route to be consumed.  Default C{False}.
        @type branch: bool


        @returns: decorated handler function.
        """
        #使用者的URL和基本URL一共幾個'/'
        segment_count = self._segments_in_url(url) + self._subroute_segments

        #裝飾器,傳回deco
        @named("router for '" + url + "'")
        def deco(f):
            kwargs.setdefault('endpoint', f.__name__)   #在kwargs裡設定鍵值對endpoint為函數名字
            if kwargs.pop('branch', False):             #如果kwargs裡存在‘branch’
                branchKwargs = kwargs.copy()            #深拷貝,一級目錄深拷貝,二級目錄淺拷貝(引用,指針)
                branchKwargs['endpoint'] = branchKwargs['endpoint'] + '_branch' #将拷貝對象的endpoint加上_branch

                @modified("branch route '{url}' executor".format(url=url), f)
                def branch_f(instance, request, *a, **kw):
                    IKleinRequest(request).branch_segments = (
                        kw.pop('__rest__', '').split('/')
                    )
                    return _call(instance, f, request, *a, **kw)    #執行函數f(*args, **kwargs) args = (instance,) + args

                branch_f.segment_count = segment_count

                self._endpoints[branchKwargs['endpoint']] = branch_f#字典儲存鍵值對(函數名字:branch_f)
                #路由分發裡添加路由
                self._url_map.add(
                    Rule(
                        url.rstrip('/') + '/' + '<path:__rest__>',#在路由末尾添加'/',確定使用者沒有添加
                        *args, **branchKwargs
                    )
                )

            @modified("route '{url}' executor".format(url=url), f)
            def _f(instance, request, *a, **kw):
                #_call就是f執行(*a,**kw)
                return _call(instance, f, request, *a, **kw)

            _f.segment_count = segment_count

            self._endpoints[kwargs['endpoint']] = _f
            self._url_map.add(Rule(url, *args, **kwargs))
            return f
        return deco
           

是兩層嵌套的裝飾器函數

segment_count就是計算routr(url)中的url有幾個'/'

#這個方法傳回一個URL裡的'/'數量
    @staticmethod
    def _segments_in_url(url):
        segment_count = url.count('/')  #一個URL裡有多少個'/'
        if url.endswith('/'):           #如果URL以'/'結尾,數量-1
            segment_count -= 1
        return segment_count
           

@name裝飾器是改變函數的__name__和__qualname__為

"router for '" + url + "'"
           
#name——"router for '" + url + "'"
#original——function
#這個裝飾器的作用是:改變函數__name__,和__qualname__,最後傳回函數
def named(name):
    """
    Change the name of a function to the given name.
    """
    def decorator(original):
        original.__name__ = str(name)
        original.__qualname__ = str(name)
        return original
    return decorator
           
@modified裝飾器是執行使用者的function(branch_f)或者function(f),并傳回結果
           
#modification "branch route '{url}' executor".format(url=url)
#original 也就是使用者的function
def modified(modification, original, modifier=None):
    #wrapper是   def branch_f(instance, request, *a, **kw)
    def decorator(wrapper):
        result = (named(modification + ' for ' + original.__name__)
                  (wraps(original)(wrapper)))#使用者function執行_f,request=_f,request就是result = f(*args, **kwargs)
        result.__original__ = original
        if modifier is not None:
            before = set(wrapper.__dict__.keys())
            result = modifier(result)
            after = set(wrapper.__dict__.keys())
            for key in after - before:
                setattr(original, key, wrapper.__dict__[key])
        return result
    return decorator

@modified("route '{url}' executor".format(url=url), f)
def _f(instance, request, *a, **kw):
#_call就是f執行(*a,**kw)
    return _call(instance, f, request, *a, **kw)
_f.segment_count = segment_count

self._endpoints[kwargs['endpoint']] = _f
self._url_map.add(Rule(url, *args, **kwargs))
return f
           

之後實作路由添加

#路由分發裡添加路由
self._url_map.add(
                    Rule(
                        url.rstrip('/') + '/' + '<path:__rest__>',#在路由末尾添加'/',確定使用者沒有添加
                        *args, **branchKwargs
                    )
                )
           

雖然Klein是twisted實作的,但是route卻不是基于twisted,正如同Flask也有route,這隻是一種設計哲學,可以學來到處用。

真正用到Twisted的,應該在于run和template,稍後在看吧。

綜上分析route實作兩個功能

  • 執行使用者函數并傳回結果
  • 實作路由對應分發