前言

最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖子,廖雪峰的课程连接在这里:廖雪峰
Python的相关介绍,以及它的历史故事和运行机制,可以参见这篇:python介绍
Python的安装可以参见这篇:Python安装
Python的运行模式以及输入输出可以参见这篇:Python IO
Python的基础概念介绍,可以参见这篇:Python 基础
Python字符串和编码的介绍,可以参见这篇:Python字符串与编码
Python基本数据结构:list和tuple介绍,可以参见这篇:Python list和tuple
Python控制语句介绍:ifelse,可以参见这篇:Python 条件判断
Python控制语句介绍:循环实现,可以参见这篇:Python循环语句
Python数据结构:dict和set介绍Python数据结构dict和set
Python函数相关:Python函数
Python高阶特性:Python高级特性
Python高阶函数:Python高阶函数
Python匿名函数:Python匿名函数
Python装饰器:Python装饰器
Python偏函数:Python偏函数
Python模块:Python模块
Python面向对象编程(1):Python面向对象
Python面向对象编程(2):Python面向对象(2)
Python面向对象编程(3):Python面向对象(3)
Python面向对象编程(4):Pyhton面向对象(4)
Python面向对象高级编程(上):Python面向对象高级编程(上)
Python面向对象高级编程(中上):Python面向对象高级编程(中上)
Python面向对象高级编程(中下):Python面向对象高级编程(中下)
Python面向对象高级编程(完):Python面向对象高级编程(完)
Python错误调试(起):Python调试:起
Python错误调试(承):Python调试:承
Python错误调试(转):Python调试:转
Python错误调试(合):python调试:合
Python文件IO编程:Python文件IO
Python文件IO编程2:Python文件IO2
Python文件IO编程3:PYthon文件IO3
Python进程和线程(起):Python进程和线程起
Python进程和线程(承):Python进程和线程承
Python进程和线程(转):Python进程和线程转
Python进程和线程(合):Python进程和线程合
Python正则表达式:Python正则表达式
Python学习笔记:常用内建模块1:Python学习笔记:常用内建模块1
Python学习笔记:常用内建模块2:Python学习笔记:常用内建模块2
Python学习笔记:常用内建模块3:Python学习笔记:常用内建模块3
Python学习笔记:常用内建模块4:Python学习笔记: 常用内建模块4
Python学习笔记:常用内建模块5:Python学习笔记: 常用内建模块5
Python学习笔记:常用内建模块6:Python学习笔记:常用内建模块6
Python学习笔记:第三方模块1:Python常用第三方模块
Python学习笔记:第三方模块2:Python常用第三方模块
Python学习笔记:第三方模块3:Python常用第三方模块
Pytho学习笔记:网络编程:Python网络编程
Python学习笔记:电子邮件:Python电子邮件1
Python学习笔记:SMTP服务器:PythonSMTP服务器
Python学习笔记:POP3服务器:PythonPOP3服务器
Python学习笔记:Python数据库 Python数据库1
Python学习笔记:Python数据库2Python数据库2
Python学习笔记:web开发1Python学习笔记:web开发1
Python学习笔记:web开发2Python学习笔记: web开发2
Python学习笔记: web开发3Python学习笔记: web开发3
Python学习笔记:异步IO(1)Python学习笔记:异步IO(1)
Python学习笔记:异步IO(2)Python学习笔记:异步IO(2)
Python学习笔记:异步IO(3)Python学习笔记:异步IO(3)
Python学习笔记:Day 1-2开发Python学习笔记:Day1-2开发
Python学习笔记:Day 3 ORMPython学习笔记:Day3 ORM
Python学习笔记:Day 4 ModelPython学习笔记:Day4Model

目录

  • 前言
  • 目录
  • web框架
  • @get和@post
  • 定义RequestHandler
  • add_routes()定义如下:
  • middleware

web框架

在正式开始Web开发前,我们需要编写一个Web框架。
aiohttp已经是一个Web框架了,为什么我们还需要自己封装一个?
原因是从使用者的角度来说,aiohttp相对比较底层,编写一个URL的处理函数需要这么几步:
第一步,编写一个用@asyncio.coroutine装饰的函数:

@asyncio.coroutine
def handle_url_xxx(request):pass

第二步,传入的参数需要自己从request中获取:

url_param = request.match_info['key']
query_params = parse_qs(request.query_string)

最后,需要自己构造Response对象:

text = render('template', data)
return web.Response(text.encode('utf-8'))

这些重复的工作可以由框架完成。例如,处理带参数的URL/blog/{id}可以这么写:

@get('/blog/{id}')
def get_blog(id):pass

处理query_string参数可以通过关键字参数**kw或者命名关键字参数接收:

@get('/api/comments')
def api_comments(*, page='1'):pass

对于函数的返回值,不一定是web.Response对象,可以是str、bytes或dict。

如果希望渲染模板,我们可以这么返回一个dict:

return {'__template__': 'index.html','data': '...'
}

因此,Web框架的设计是完全从使用者出发,目的是让使用者编写尽可能少的代码。

编写简单的函数而非引入request和web.Response还有一个额外的好处,就是可以单独测试,否则,需要模拟一个request才能测试。

@get和@post

要把一个函数映射为一个URL处理函数,我们先定义@get():

def get(path):'''Define decorator @get('/path')'''def decorator(func):@functools.wraps(func)def wrapper(*args, **kw):return func(*args, **kw)wrapper.__method__ = 'GET'wrapper.__route__ = pathreturn wrapperreturn decorator

这样,一个函数通过@get()的装饰就附带了URL信息。

@post与@get定义类似。

定义RequestHandler

URL处理函数不一定是一个coroutine,因此我们用RequestHandler()来封装一个URL处理函数。

RequestHandler是一个类,由于定义了call()方法,因此可以将其实例视为函数。

RequestHandler目的就是从URL函数中分析其需要接收的参数,从request中获取必要的参数,调用URL函数,然后把结果转换为web.Response对象,这样,就完全符合aiohttp框架的要求:

class RequestHandler(object):def __init__(self, app, fn):self._app = appself._func = fn...@asyncio.coroutinedef __call__(self, request):kw = ... 获取参数r = yield from self._func(**kw)return r

再编写一个add_route函数,用来注册一个URL处理函数:

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

最后一步,把很多次add_route()注册的调用:

add_route(app, handles.index)
add_route(app, handles.blog)
add_route(app, handles.create_comment)
...

变成自动扫描:

# 自动把handler模块的所有符合条件的函数注册了:
add_routes(app, 'handlers')

add_routes()定义如下:

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('_'):continuefn = getattr(mod, attr)if callable(fn):method = getattr(fn, '__method__', None)path = getattr(fn, '__route__', None)if method and path:add_route(app, fn)

最后,在app.py中加入middleware、jinja2模板和自注册的支持:

app = web.Application(loop=loop, middlewares=[logger_factory, response_factory
])
init_jinja2(app, filters=dict(datetime=datetime_filter))
add_routes(app, 'handlers')
add_static(app)

middleware

middleware是一种拦截器,一个URL在被某个函数处理前,可以经过一系列的middleware的处理。

一个middleware可以改变URL的输入、输出,甚至可以决定不继续处理而直接返回。middleware的用处就在于把通用的功能从每个URL处理函数中拿出来,集中放到一个地方。例如,一个记录URL日志的logger可以简单定义如下:

@asyncio.coroutine
def logger_factory(app, handler):@asyncio.coroutinedef logger(request):# 记录日志:logging.info('Request: %s %s' % (request.method, request.path))# 继续处理请求:return (yield from handler(request))return logger

而response这个middleware把返回值转换为web.Response对象再返回,以保证满足aiohttp的要求:

@asyncio.coroutine
def response_factory(app, handler):@asyncio.coroutinedef response(request):# 结果:r = yield from handler(request)if isinstance(r, web.StreamResponse):return rif isinstance(r, bytes):resp = web.Response(body=r)resp.content_type = 'application/octet-stream'return respif isinstance(r, str):resp = web.Response(body=r.encode('utf-8'))resp.content_type = 'text/html;charset=utf-8'return respif isinstance(r, dict):...

有了这些基础设施,我们就可以专注地往handlers模块不断添加URL处理函数了,可以极大地提高开发效率。

Python学习笔记:Day5 编写web框架相关推荐

  1. Python学习笔记 day5

    Python学习笔记 day5 参考/引用资料: 1.file a.打开文件方式(读写两种方式) 缓冲 with语句 b.文件对象的操作方法 c.学习对excel及csv文件进行操作 读写excel ...

  2. python学习笔记之编写readConfig读写配置文件

    python学习笔记之编写readConfig读写配置文件_weixin_34055910的博客-CSDN博客

  3. Python学习-基础篇14 Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  4. python学习随笔--web框架

    Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python #coding:utf- ...

  5. Python学习笔记——爬虫之Scrapy框架

    目录 Scrapy 框架 Scrapy的安装介绍 Windows 安装方式 Ubuntu 需要9.10或以上版本安装方式 入门案例 启动Scrapy Shell Item Pipeline Spide ...

  6. Python学习笔记-实现探测Web服务质量

    pycurl是一个用C语言写的libcurl Python实现,功能非常强大,支持的操作协议后FTP.HTTP.HTTPS.TELNET等,可以理解成Linux下curl命令功能的Python封装,简 ...

  7. python学习笔记-Day5

    字符串格式化 # 字符串格式化之%占位符# a. 位置 s = 'i am %s age %d' % ('eason', 18) print(s)==> i am eason age 18 # ...

  8. Python学习笔记:Day 16 编写移动App

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  9. Python学习笔记:Day15 部署Web App

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

最新文章

  1. 前后端对接的思考及总结
  2. kmeans中的k的含义_聚类的Python实现(二):确定分群数K
  3. C#.NET常见问题(FAQ)-Combobox如何设置不可以编辑
  4. Windows坐标系统
  5. ext 不能修改 输入框_在extjs中,如何用method改变textfield中inputType的问题
  6. VGG16—perceptual loss in keras感知损失【Keras】
  7. SQL SERver2005中row_number() 的用法
  8. 在 Windows Azure 虚拟机上运行 SQL Server 工作负荷的十大注意事项
  9. EBS Sql Loader的简单使用
  10. Nginx 架构原理
  11. CSDN x BSV|区块链工程师能力初级认证正式启动
  12. window定时自动关机脚本及问题解决【AT指令和SCHTASKS指令两种方式】
  13. 原来电路最高工作频率是这么算出来的(STA基础篇)
  14. 技术系统进化法则包括_TRIZ理论八大技术系统进化法则.doc
  15. Win10离线安装.NET Framework 3.5的方法总结
  16. 软件测试基础-Web前端(二)
  17. 如何正确下载安装eclipse(java常用的编程开发软件)?
  18. |app自动化测试之Appium问题分析及定位
  19. c语言改错题字符串a放在b后面,C语言程序改错题汇总.doc
  20. H5网页头部的声明应该是用 lang=zh 还是 lang=zh-cn?

热门文章

  1. degree of freedom of a leg of a dog
  2. gscatter in matlab Scatter plot by group machine learning and statics tool box required
  3. CSSE*PTC student tutoring program student lecturers of 2018-2019 Academic Year.
  4. 利用叉乘快速判断点是否在三角形内
  5. redhat6.5 yum register 问题
  6. 17.Node.js 回调函数--异步编程
  7. skynet 报错 skynet 服务缺陷 Lua死循环
  8. PHP实习之路—NO.1(看LINUX、APACHE、MYSQL、PHP文档)
  9. 算法题:找出整数数组中两个只出现一次的数字
  10. NSUserDefault 的使用