Python学习笔记:Day5 编写web框架
前言
最近在學習深度學習,已經跑出了幾個模型,但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裝飾的函數:
第二步,傳入的參數需要自己從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框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java合并多个表格为一个_多个Data
- 下一篇: websocket python爬虫_p