zoukankan      html  css  js  c++  java
  • 廖大python实战项目第五天

    PS: 决定还是坚持写博客记录一下比较好。

    今天的实战内容是编写web框架,如果之前的知识不熟悉的话确实看不大懂。在这里奉上自己的理解以及帮助理解的相关资料和文档。


    Web框架

    首先我们要知道web框架是什么东西,它到底要怎么实现。这一点廖大在web开发的WSGI接口使用web框架这两篇文章里已经说过了。摘要一些略作说明:

    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<h1>Hello, web!</h1>']
    

    上面这段代码实现了响应HTTP请求,其中start_response 发送了HTTP响应的Headerreturn 则将HTTP响应的body 返回。在这里面,如何接受、解析HTTP请求和发送HTTP响应不是我们关注的重点,我们该做的是决定用什么内容去响应HTTP请求,而其余部分交给WSGI接口去实现。这里已经出现了第一层的抽象,让我们摆脱烦杂的底层逻辑。

    然而单单实现这个还是不够的,对比WebApp的处理逻辑,这里还是有些低级。一个url对应一个HTTP请求,而HTTP请求可分为GET,POST,PUT,DELETE等等,我们自己用一个一个的函数实现不大现实。所以我们需要对WSGI接口做进一步的抽象,也就是所谓的Web框架

    回到廖大的这一天的实战内容,是要对aiohttp封装一个更高层次的web框架。为了看懂aiohttp实现HTTP响应的逻辑(整体和同步一样但是还是有一些差别影响理解),我们需要先把之前的异步IO那四篇都回顾一下,在这里,aiohttp官方文档还有Server Usage可以帮助我们更好地理解request,Response,Application这三个方法的功能。

    涉及到模块渲染装饰器我一开始有些不清楚,补一下对应的章节就明白了。


    __call__()方法

    廖大提到一个方法__call()__,只要一个类定义了这个方法,就可以将它的实例视为函数。这里先上一篇文章Python的特殊函数 __call()__算是讲得很清楚了。python中函数是一个对象,与普通类的实例不同的是,函数是callable;但只要给一个类添上__call()__方法,就可以实现像函数那样的调用。


    getattr()方法

    这个方法在前两天的实战中已经见过,但还是补一下资料内容。文章:Python的hasattr(), getattr(), setattr()函数使用方法详解

    getattr()是用于获取对象的属性或方法,如果存在就打印出来,如果不存在就打印出默认值。需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,可以在后面添加一对括号。


    inspect模块

    参考:
    Python文档--inspect模块介绍
    中文版inspect模块介绍

    在这段实例中:

    def add_route(app, fn):
        method = getattr(fn, '__method__', None)
        path = getattr(fn, '__route__', None)
        if path is None or method is None:
            raise ValueError('@get or @post not defined in %s.' % str(fn))
        if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn):
            fn = asyncio.coroutine(fn)
        logging.info('add route %s %s => %s(%s)' % (method, path, fn.__name__, ', '.join(inspect.signature(fn).parameters.keys())))
        app.router.add_route(method, path, RequestHandler(app, fn))
    

    廖大用到了之前没见过的inspect模块。其中inspect.isgeneratorfunction()好理解,从字面上可以知道是判断是否为generaor函数。具体的实现暂时不去管它。

    后面那个inspect.signature(fn).parameters.keys()有点费解。其中inspect.signature()的功能根据官方文档讲是Return a Signature object for the given callable,即返回传入的可调用函数的所有参数;而之后的paramters似乎是用于索引参数。这是官方的两个示例:

    关于signature

    >>> from inspect import signature
    >>> def foo(a, *, b:int, **kwargs):
    ...     pass
    
    >>> sig = signature(foo)
    
    >>> str(sig)
    '(a, *, b:int, **kwargs)'
    
    >>> str(sig.parameters['b'])
    'b:int'
    
    >>> sig.parameters['b'].annotation
    <class 'int'>
    

    关于parameter

    >>> def foo(a, b, *, c, d=10):
    ...     pass
    
    >>> sig = signature(foo)
    >>> for param in sig.parameters.values():
    ...     if (param.kind == param.KEYWORD_ONLY and
    ...                        param.default is param.empty):
    		# KEYWORD_ONLY: 关键字参数
    ...         print('Parameter:', param)
    Parameter: c
    

    所以,廖大的那段代码的意思是将函数的所有参数(不包括默认值)用逗号隔开,加入到那个括号里去。


    rfind()方法

    从右向左查询,返回字符串首次出现的位置;如果没有匹配项则返回-1。
    find()与之类似,只不过是从左向右查询。


    __import__()

    参考:
    Python官方文档
    __import__中文介绍

    __import__内置函数是用于动态加载模块的。这个不难理解,关键是理解廖大的示例:

    def add_routes(app, module_name):
    	n = module_name.rfind('.')  # 找到模块名的最后一个'.'位置
        if n == (-1):               # 如果模块名为“XX”这种形式
            mod = __import__(module_name, globals(), locals())
        else:                       # 如果模块名为"XX.XX"这种形式
            name = module_name[n+1:] # 后半部分即子函数
            mod = getattr(__import__(module_name[:n], globals(), locals(), [name]), name)         # 加载模块,获取模块的子函数并返回
        for attr in dir(mod):        # 对于子函数里的所有属性和方法
            if attr.startswith('_'): # 如果attr为”__XX"这种形式就忽略
                continue
            fn = getattr(mod, attr)
            if callable(fn):         # 如果可调用
                method = getattr(fn, '__method__', None)
                path = getattr(fn, '__route__', None)
                if method and path:
                    add_route(app, fn)
    

    拦截器

    拦截器廖大python实战项目第五天

  • 相关阅读:
    P4005 小 Y 和地铁
    P1039 侦探推理
    P2766 最长不下降子序列问题
    P2312 解方程
    P2169 正则表达式
    UOJ#22. 【UR #1】外星人
    UOJ#21. 【UR #1】缩进优化
    Palindromeness CodeChef
    bzoj5392 [Lydsy1806月赛]路径统计
    997D Cycles in product
  • 原文地址:https://www.cnblogs.com/ChanWunsam/p/10018256.html
Copyright © 2011-2022 走看看