且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Day 5 - 编写Web框架 代码优化

更新时间:2022-09-08 21:15:35

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):

    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 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,如需转载请自行联系原作者