Python学习笔记:Day5 编写web框架
前言
最近在學習深度學習,已經(jīng)跑出了幾個模型,但Pyhton的基礎(chǔ)不夠扎實,因此,開始補習Python了,大家都推薦廖雪峰的課程,因此,開始了學習,但光學有沒有用,還要和大家討論一下,因此,寫下這些帖子,廖雪峰的課程連接在這里:廖雪峰
Python的相關(guān)介紹,以及它的歷史故事和運行機制,可以參見這篇:python介紹
Python的安裝可以參見這篇:Python安裝
Python的運行模式以及輸入輸出可以參見這篇:Python IO
Python的基礎(chǔ)概念介紹,可以參見這篇:Python 基礎(chǔ)
Python字符串和編碼的介紹,可以參見這篇:Python字符串與編碼
Python基本數(shù)據(jù)結(jié)構(gòu):list和tuple介紹,可以參見這篇:Python list和tuple
Python控制語句介紹:ifelse,可以參見這篇:Python 條件判斷
Python控制語句介紹:循環(huán)實現(xiàn),可以參見這篇:Python循環(huán)語句
Python數(shù)據(jù)結(jié)構(gòu):dict和set介紹Python數(shù)據(jù)結(jié)構(gòu)dict和set
Python函數(shù)相關(guān):Python函數(shù)
Python高階特性:Python高級特性
Python高階函數(shù):Python高階函數(shù)
Python匿名函數(shù):Python匿名函數(shù)
Python裝飾器:Python裝飾器
Python偏函數(shù):Python偏函數(shù)
Python模塊:Python模塊
Python面向?qū)ο缶幊?#xff08;1):Python面向?qū)ο?
Python面向?qū)ο缶幊?#xff08;2):Python面向?qū)ο?#xff08;2)
Python面向?qū)ο缶幊?#xff08;3):Python面向?qū)ο?#xff08;3)
Python面向?qū)ο缶幊?#xff08;4):Pyhton面向?qū)ο?#xff08;4)
Python面向?qū)ο蟾呒壘幊?#xff08;上):Python面向?qū)ο蟾呒壘幊?#xff08;上)
Python面向?qū)ο蟾呒壘幊?#xff08;中上):Python面向?qū)ο蟾呒壘幊?#xff08;中上)
Python面向?qū)ο蟾呒壘幊?#xff08;中下):Python面向?qū)ο蟾呒壘幊?#xff08;中下)
Python面向?qū)ο蟾呒壘幊?#xff08;完):Python面向?qū)ο蟾呒壘幊?#xff08;完)
Python錯誤調(diào)試(起):Python調(diào)試:起
Python錯誤調(diào)試(承):Python調(diào)試:承
Python錯誤調(diào)試(轉(zhuǎn)):Python調(diào)試:轉(zhuǎn)
Python錯誤調(diào)試(合):python調(diào)試:合
Python文件IO編程:Python文件IO
Python文件IO編程2:Python文件IO2
Python文件IO編程3:PYthon文件IO3
Python進程和線程(起):Python進程和線程起
Python進程和線程(承):Python進程和線程承
Python進程和線程(轉(zhuǎn)):Python進程和線程轉(zhuǎn)
Python進程和線程(合):Python進程和線程合
Python正則表達式:Python正則表達式
Python學習筆記:常用內(nèi)建模塊1:Python學習筆記:常用內(nèi)建模塊1
Python學習筆記:常用內(nèi)建模塊2:Python學習筆記:常用內(nèi)建模塊2
Python學習筆記:常用內(nèi)建模塊3:Python學習筆記:常用內(nèi)建模塊3
Python學習筆記:常用內(nèi)建模塊4:Python學習筆記: 常用內(nèi)建模塊4
Python學習筆記:常用內(nèi)建模塊5:Python學習筆記: 常用內(nèi)建模塊5
Python學習筆記:常用內(nèi)建模塊6:Python學習筆記:常用內(nèi)建模塊6
Python學習筆記:第三方模塊1:Python常用第三方模塊
Python學習筆記:第三方模塊2:Python常用第三方模塊
Python學習筆記:第三方模塊3:Python常用第三方模塊
Pytho學習筆記:網(wǎng)絡(luò)編程:Python網(wǎng)絡(luò)編程
Python學習筆記:電子郵件:Python電子郵件1
Python學習筆記:SMTP服務(wù)器:PythonSMTP服務(wù)器
Python學習筆記:POP3服務(wù)器:PythonPOP3服務(wù)器
Python學習筆記:Python數(shù)據(jù)庫 Python數(shù)據(jù)庫1
Python學習筆記:Python數(shù)據(jù)庫2Python數(shù)據(jù)庫2
Python學習筆記:web開發(fā)1Python學習筆記:web開發(fā)1
Python學習筆記:web開發(fā)2Python學習筆記: web開發(fā)2
Python學習筆記: web開發(fā)3Python學習筆記: web開發(fā)3
Python學習筆記:異步IO(1)Python學習筆記:異步IO(1)
Python學習筆記:異步IO(2)Python學習筆記:異步IO(2)
Python學習筆記:異步IO(3)Python學習筆記:異步IO(3)
Python學習筆記:Day 1-2開發(fā)Python學習筆記:Day1-2開發(fā)
Python學習筆記:Day 3 ORMPython學習筆記:Day3 ORM
Python學習筆記:Day 4 ModelPython學習筆記:Day4Model
目錄
- 前言
- 目錄
- web框架
- @get和@post
- 定義RequestHandler
- add_routes()定義如下:
- middleware
web框架
在正式開始Web開發(fā)前,我們需要編寫一個Web框架。
aiohttp已經(jīng)是一個Web框架了,為什么我們還需要自己封裝一個?
原因是從使用者的角度來說,aiohttp相對比較底層,編寫一個URL的處理函數(shù)需要這么幾步:
第一步,編寫一個用@asyncio.coroutine裝飾的函數(shù):
第二步,傳入的參數(shù)需要自己從request中獲取:
url_param = request.match_info['key'] query_params = parse_qs(request.query_string)最后,需要自己構(gòu)造Response對象:
text = render('template', data) return web.Response(text.encode('utf-8'))這些重復的工作可以由框架完成。例如,處理帶參數(shù)的URL/blog/{id}可以這么寫:
@get('/blog/{id}') def get_blog(id):pass處理query_string參數(shù)可以通過關(guān)鍵字參數(shù)**kw或者命名關(guān)鍵字參數(shù)接收:
@get('/api/comments') def api_comments(*, page='1'):pass對于函數(shù)的返回值,不一定是web.Response對象,可以是str、bytes或dict。
如果希望渲染模板,我們可以這么返回一個dict:
return {'__template__': 'index.html','data': '...' }因此,Web框架的設(shè)計是完全從使用者出發(fā),目的是讓使用者編寫盡可能少的代碼。
編寫簡單的函數(shù)而非引入request和web.Response還有一個額外的好處,就是可以單獨測試,否則,需要模擬一個request才能測試。
@get和@post
要把一個函數(shù)映射為一個URL處理函數(shù),我們先定義@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這樣,一個函數(shù)通過@get()的裝飾就附帶了URL信息。
@post與@get定義類似。
定義RequestHandler
URL處理函數(shù)不一定是一個coroutine,因此我們用RequestHandler()來封裝一個URL處理函數(shù)。
RequestHandler是一個類,由于定義了call()方法,因此可以將其實例視為函數(shù)。
RequestHandler目的就是從URL函數(shù)中分析其需要接收的參數(shù),從request中獲取必要的參數(shù),調(diào)用URL函數(shù),然后把結(jié)果轉(zhuǎn)換為web.Response對象,這樣,就完全符合aiohttp框架的要求:
class RequestHandler(object):def __init__(self, app, fn):self._app = appself._func = fn...@asyncio.coroutinedef __call__(self, request):kw = ... 獲取參數(shù)r = yield from self._func(**kw)return r再編寫一個add_route函數(shù),用來注冊一個URL處理函數(shù):
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()注冊的調(diào)用:
add_route(app, handles.index) add_route(app, handles.blog) add_route(app, handles.create_comment) ...變成自動掃描:
# 自動把handler模塊的所有符合條件的函數(shù)注冊了: 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在被某個函數(shù)處理前,可以經(jīng)過一系列的middleware的處理。
一個middleware可以改變URL的輸入、輸出,甚至可以決定不繼續(xù)處理而直接返回。middleware的用處就在于把通用的功能從每個URL處理函數(shù)中拿出來,集中放到一個地方。例如,一個記錄URL日志的logger可以簡單定義如下:
@asyncio.coroutine def logger_factory(app, handler):@asyncio.coroutinedef logger(request):# 記錄日志:logging.info('Request: %s %s' % (request.method, request.path))# 繼續(xù)處理請求:return (yield from handler(request))return logger而response這個middleware把返回值轉(zhuǎn)換為web.Response對象再返回,以保證滿足aiohttp的要求:
@asyncio.coroutine def response_factory(app, handler):@asyncio.coroutinedef response(request):# 結(jié)果: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):...有了這些基礎(chǔ)設(shè)施,我們就可以專注地往handlers模塊不斷添加URL處理函數(shù)了,可以極大地提高開發(fā)效率。
總結(jié)
以上是生活随笔為你收集整理的Python学习笔记:Day5 编写web框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java合并多个表格为一个_多个Data
- 下一篇: Python学习笔记:Day 6 配置文