萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> 編程語言綜合 >> 解讀Python的web.py框架下的application.py模塊

解讀Python的web.py框架下的application.py模塊

   這篇文章主要介紹了Python的web.py框架下的application.py模塊,作者深入分析了web.py的源碼,需要的朋友可以參考下

  本文主要分析的是web.py庫的application.py這個模塊中的代碼。總的來說,這個模塊主要實現了WSGI兼容的接口,以便應用程序能夠被WSGI應用服務器調用。WSGI是Web Server Gateway Interface的縮寫,具體細節可以查看WSGI的WIKI頁面

  接口的使用

  使用web.py自帶的HTTP Server

  下面這個例子來自官方文檔的Hello World,這個代碼一般是應用入口的代碼:

  ?

1 2 3 4 5 6 7 8 9 10 11 import web   urls = ("/.*", "hello") app = web.application(urls, globals())   class hello: def GET(self): return 'Hello, world!'   if __name__ == "__main__": app.run()

  上面的例子描述了一個web.py應用最基本的組成元素:

  URL路由表

  一個web.application實例app

  調用app.run()

  其中,app.run()的調用是初始化各種WCGI接口,並啟動一個內置的HTTP服務器和這些接口對接,代碼如下:

  ?

1 2 def run(self, *middleware): return wsgi.runwsgi(self.wsgifunc(*middleware))

  與WSGI應用服務器對接

  如果你的應用要與WSGI應用服務器對接,比如uWSGI,gunicorn等,那麼應用入口的代碼就要換一種寫法了:

  ?

1 2 3 4 5 6 7 8 9 import web   class hello: def GET(self): return 'Hello, world!'   urls = ("/.*", "hello") app = web.application(urls, globals()) application = app.wsgifunc()

  在這種場景下,應用的代碼不需要啟動HTTP服務器,而是實現一個WSGI兼容的接口供WSGI服務器調用。web.py框架為我們實現了這樣的接口,你只需要調用application = app.wsgifunc()就可以了,這裡所得到的application變量就是WSGI接口(後面分析完代碼你就會知道了)。

  WSGI接口的實現分析

  分析主要圍繞著下面兩行代碼進行:

  ?

1 2 app = web.application(urls, globals()) application = app.wsgifunc()

  web.application實例化

  初始化這個實例需要傳遞兩個參數:URL路由元組和globals()的結果。

  另外,還可以傳遞第三個變量:autoreload,用來指定是否需要自動重新導入Python模塊,這在調試的時候很有用,不過我們分析主要過程的時候可以忽略。

  application類的初始化代碼如下:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 class application: def __init__(self, mapping=(), fvars={}, autoreload=None): if autoreload is None: autoreload = web.config.get('debug', False) self.init_mapping(mapping) self.fvars = fvars self.processors = []   self.add_processor(loadhook(self._load)) self.add_processor(unloadhook(self._unload))   if autoreload: ...

  其中,autoreload相關功能的代碼略去了。其他的代碼主要作了如下幾個事情:

  self.init_mapping(mapping):初始化URL路由映射關系。

  self.add_processor():添加了兩個處理器。

  初始化URL路由映射關系

  ?

1 2 def init_mapping(self, mapping): self.mapping = list(utils.group(mapping, 2))

  這個函數還調用了一個工具函數,效果是這樣的:

  ?

1 2 3 urls = ("/", "Index", "/hello/(.*)", "Hello", "/world", "World")

  如果用戶初始化時傳遞的元組是這樣的,那麼調用init_mapping之後:

  ?

1 2 3 self.mapping = [["/", "Index"], ["/hello/(.*)", "Hello"], ["/world", "World"]]

  後面框架在進行URL路由時,就會遍歷這個列表。

  添加處理器

  ?

1 2 self.add_processor(loadhook(self._load)) self.add_processor(unloadhook(self._unload))

  這兩行代碼添加了兩個處理器:self._load和self._unload,而且還對這兩個函數進行了裝飾。處理器的是用在HTTP請求處理前後的,它不是真正用來處理一個HTTP請求,但是可以用來作一些額外的工作,比如官方教程裡面有提到的給子應用添加session的做法,就是使用了處理器:

  ?

1 2 3 4 def session_hook(): web.ctx.session = session   app.add_processor(web.loadhook(session_hook))

  處理器的定義和使用都是比較復雜的,後面專門講。

  wsgifunc函數

  wsgifunc的執行結果是返回一個WSGI兼容的函數,並且該函數內部實現了URL路由等功能。

  ?

1 2 3 4 5 6 7 def wsgifunc(self, *middleware): """Returns a WSGI-compatible function for this application.""" ... for m in middleware: wsgi = m(wsgi)   return wsgi

  除開內部函數的定義,wsgifunc的定義就是這麼簡單,如果沒有實現任何中間件,那麼就是直接返回其內部定義的wsgi函數。

  wsgi函數

  該函數實現了WSGI兼容接口,同時也實現了URL路由等功能。

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 def wsgi(env, start_resp): # clear threadl
copyright © 萬盛學電腦網 all rights reserved