天天看點

Day 5 - 編寫Web架構 代碼優化

1.匿名sina網友V 

廖大的版本

def add_routes(app, module_name):

    n = module_name.rfind('.')

    if n == (-1):

        mod = __import__(module_name, globals(), locals())

    else:

        name = module_name[n+1:]

        mod = getattr(__import__(module_name[:n], globals(), locals(), [name]), name)

    for attr in dir(mod):

        if attr.startswith('_'):

            continue

        fn = getattr(mod, attr)

        if callable(fn):

        #這裡用callable區分函數和普通成員變量是不合适地。

        #總是有一些奇怪的東西混進來,例如handler裡邊引入的User 用callable判斷它總是True,然而掃描User純粹是浪費電。

            method = getattr(fn, '__method__', None)

            path = getattr(fn, '__route__', None)

            if method and path:

            #這裡method和path 判斷完就丢了,有點可惜,add_route()裡邊還要再費二遍事,最好能修改add_route的簽名,add_route(app,fn,method,path)一套傳過去。

                add_route(app, fn)

我改過的

import types

def add_routes(app,module_name):

        mod = __import__(module_name,globals(),locals())

        mod = getattr(__import__(module_name[:n],globals(),locals(),[name]),name)

        fn = getattr(mod , attr)

        if isinstance(fn,types.FunctionType):

            has_method = hasattr(fn,"__method__")

            has_path = hasattr(fn,"__route__")

            if has_method and has_path:

                add_route(app,fn)

2.middleware和RequestHandler是一定要實作的,不然耦合度太高很容易混亂。

相反,add_route可以省略,如果隻加一個的話app.router.add_route就足以應付了。

這是我重構過的版本, __import__有一個黑魔法,不用寫得這麼複雜的:

mod = __import__(module_name, fromlist=[''])

叫做mblog-master

github位址 https://github.com/moling3650/mblog

3.你的add_routes()很機智,廖大版的method 和 path 查到了不用實在是浪費。

RequestHandler看起來寫得和廖大的結構上不一樣,粗略的摟了兩眼,兩份我都沒仔細看具體實作。

在這裡我得黑一下廖大,廖大版的RequestHandler 貌似把handler函數的參數名寫死了,handler的參數必須得叫request。我感覺這樣對使用者不太友好,這是對使用者赤裸裸地強J。

最好能用判斷類型的方法來代替判斷參數名的方法,來保證傳入了一個request類型的參數。這樣使用者寫handler的時候就r,req,request 什麼的随意寫了。使用者用得爽了,架構才有市場。

4.https://github.com/moling3650/mblog

效果圖

http://www.qiangtaoli.com/bootstrap/manage/blogs

我的已經是做完了,而且重構了不少地方,比如RequestHandler,重構的理由在這裡。

你黑的并不是地方,不是handler函數的參數寫死了,而是app.router.add_route方法的第三個參數寫死了,這裡必需是一個隻有一個參數request的函數,是以才用__call__統一封裝成RequestHandler(handler)(request)的形式,這樣使得handler的參數可以多樣化。

然而RequestHandler是整個項目中最值得黑的地方,你可以看看我和别人在樓下的評論就會知道真正值得黑的地方在哪裡了XD

5.add_routes最後直接用一個if更簡潔

if isinstance(fn, types.FunctionType) and hasattr(fn, '__method__') and hasattr(fn, '__route__'):

    add_route(app, fn)

6.你沒讀過asyncio的源碼才會這樣說,func = asyncio.coroutine(func)這方法會内部處理func是協程或生成器,根本無需在外先判斷func的類型,最終出來的就是标準的協程函數。

在add_routes都用了method = getattr(func, '__method__', None)了,還要在add_route進行hasattr(fn, '__method__')判斷是沒有意義的,在add_routes中沒有__method__和__route__屬性時根本不會調用add_route

add_route這些判斷是為單獨調用時存在的,然而并沒有單獨調用的場景。有單獨調用的場景我倒不如直接用pp.router.add_route了。

7.看明白了,你隻需要簡單判斷一下callable就可以丢給add_route處理就行了,hasattr(fn, '__method__') and hasattr(fn, '__route__')放在add_route處理就好。

8.async def logger_factory(app, handler): #這就是個裝飾器呀

    async def logger(request):

        logging.info('Request: %s %s Begin>>>' % (request.method, request.path))

        # await asyncio.sleep(0.3)

        rst = (await handler(request))

        return rst

    return logger

async def response_factory(app, handler): #這個middleware比較不錯,大家在handler裡邊可以傳回各種類型的結果,在這裡統一由廖大的response_factory給大家擦屁股。

    。。。

middleware的代碼示意:

m1( m2( m3( doFoo())))

middleware調用流程:

req -> m1 -> m2 -> m3 -> doFoo()- 一路return 原路傳回

<- m1 <- m2 <- m2 <- resq - <-

本文轉自 liqius 51CTO部落格,原文連結:http://blog.51cto.com/szgb17/1943522,如需轉載請自行聯系原作者