摘要:模板函數到底長什么樣下面我們就可以來看看模板函數到底長什么樣了。當然,首先得創(chuàng)建一個模板文件??偨Y通過打印中間結果和分析代碼,我們已經大概知道了的模板是如何轉化成內容的。下一篇文章會闡述模板的各種語法所對應的動態(tài)函數內容。
web.py模板的實現原理
web.py的模板實現利用了Python的可執(zhí)行對象的動態(tài)特性:根據模板內容和渲染函數的參數創(chuàng)建一個函數,該函數執(zhí)行的時候會返回一個TemplateResult類實例,該實例的字符串化就是模板對應的HTML內容。
實驗環(huán)境搭建為了說明web.py的模板是如何實現的,我們需要在web.py的模板實現代碼中加入一些打印語句來顯示中間結果。Python的virtualenv工具很好的實現了這個需求。另外,我還使用了iPython,不過Python標準命令行也是可以的。環(huán)境搭建的步驟簡述如下:
創(chuàng)建virtualenv環(huán)境:virtualenv env
激活virtualenv環(huán)境:cd env以及source bin/activate
安裝web.py:pip install web.py
這個web.py庫會被安裝在virtualenv環(huán)境的目錄下:
(env)? ~/programming/python/env/lib/python2.7/site-packages/web $ pwd /home/diabloneo/programming/python/env/lib/python2.7/site-packages/web
下面就可以修改這個web.py的代碼來看看模板到底是如何實現的。
實驗代碼修改我們要修改的代碼位于web/template.py文件內,找到Template類的compile_template函數(在template.py文件的第900行),加入一行打印語句:
def compile_template(self, template_string, filename): code = Template.generate_code(template_string, filename, parser=self.create_parser()) def get_source_line(filename, lineno): try: lines = open(filename).read().splitlines() return lines[lineno] except: return None print code # 這行就是我們增加的調試語句,可以打印出前面提到的動態(tài)生成的函數。 try: # compile the code first to report the errors, if any, with the filename compiled_code = compile(code, filename, "exec") except SyntaxError, e: ...模板函數到底長什么樣?
下面我們就可以來看看模板函數到底長什么樣了。當然,首先得創(chuàng)建一個模板文件。在我們的實驗環(huán)境中進行如下操作:
(env)? ~/programming/python/env $ ls bin include lib local (env)? ~/programming/python/env $ mkdir app (env)? ~/programming/python/env $ ls app bin include lib local (env)? ~/programming/python/env $ cd app (env)? ~/programming/python/env/app $ mkdir templates
現在,在templates目錄下創(chuàng)建一個最簡單的模板,文件名為hello.html,內容如下:
hello, world
下面來看看根據這個模板生成的函數到底長什么樣子,在實驗環(huán)境下啟動ipython或者python,進入到app目錄:
(env)? ~/programming/python/env/app $ ipython WARNING: Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv. Python 2.7.8 (default, Oct 20 2014, 15:05:19) Type "copyright", "credits" or "license" for more information. IPython 1.0.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython"s features. %quickref -> Quick reference. help -> Python"s own help system. object? -> Details about "object", use "object??" for extra details. In [1]:
執(zhí)行如下代碼就可以看到模板函數的內容:
In [3]: hello = web.template.frender("templates/hello.html") # coding: utf-8 def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u"hello, world "]) return self In [4]:
上面的函數__template__()就是我們增加到web.py庫中的那行print code所打印出來的。從這個函數的定義,我們可以看出:
函數內使用了一些預定義的對象:ForLoop,TemplateResult等。
函數的結果是返回一個TemplateResult實例。
那么,現在問題來了:
這個函數是如何生成的?
使用的這些預定義名稱從哪里來的?
TemplateResult實例的字符串表示如何變成HTML文本的?
本文先來說明TemplateResult實例是如何產生HTML文本這個問題。
TemplateResultTemplateResult類的定義也在web/template.py文件中,繼承的類和實現的方法如下:
class TemplateResult(object, DictMixin): __delattr__ : function __delitem__ : function __getattr__ : function __getitem__ : function __init__ : function __repr__ : function __setattr__ : function __setitem__ : function __str__ : function __unicode__ : function _prepare_body : function keys : function
其中DictMixin是一個實現了大部分字典操作的類,繼承該類的子類(也就是這里的TemplateResult)需要實現:__getitem__(), __setitem__(), __delitem__()和keys()方法,以便對象可以模擬完整的字典操作。需要說明的是:DictMixin類已經過時了,現在應該使用collections.MutableMapping類(該類的實現利用了abc庫--抽象類)。
先來看__init__()函數,
def __init__(self, *a, **kw): self.__dict__["_d"] = dict(*a, **kw) self._d.setdefault("__body__", u"") self.__dict__["_parts"] = [] self.__dict__["extend"] = self._parts.extend
從初始化函數可以看出,TemplateResult大部分屬性都存儲在_d這個字典中,該字典至少包含一個元素body。所以,外部代碼對TemplateResult的對象屬性進行增刪改查操作時,實際上都是在操作內部的_d這個字典。初始化函數中定義的另外兩個屬性是:_parts,一個序列;extend,指向_parts序列的extend()方法,也就是說調用TemplateResult實例的extend方法實際上是調用實例屬性_parts的extend方法。這個extend方法我們在前面的__template__()函數已經見到過了:
def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u"hello, world "]) return self
這個函數定義了extend_ = self.extend,extend_把模板的內容添加到了self._parts這個序列中。
下面來看一下TemplateResult如何生成HTML內容,這個就要看__str__()方法了:
def _prepare_body(self): """Prepare value of __body__ by joining parts. """ if self._parts: value = u"".join(self._parts) self._parts[:] = [] body = self._d.get("__body__") if body: self._d["__body__"] = body + value else: self._d["__body__"] = value def __str__(self): self._prepare_body() return self["__body__"].encode("utf-8")
主要操作是在_prepare_body()函數里,主要操作是把_parts中的字符串拼接起來,然后再拼接到body的內容后面。
看過TemplateResult的實現后,我們可以知道,由模板生成的__template__()函數最終會把一堆字符串添加到TemplateResult實例中,然后再通過實例生成HTML字符串。
總結通過打印中間結果和分析代碼,我們已經大概知道了web.py的模板是如何轉化成HTML內容的。下一篇文章會闡述web.py模板的各種語法所對應的動態(tài)函數內容。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/45359.html
摘要:上一篇文章源碼分析模板說明了的模板的大致工作原理。本文重點講述模板支持的語法是如何轉換生成函數的。模板的名稱統(tǒng)一是。模板代碼斷行模板內容函數內容從結果來看,模板中的斷行只是為了不再結果中插入一個多余的換行符而已。 上一篇文章web.py源碼分析: 模板(1)說明了web.py的模板的大致工作原理。本文重點講述web.py模板支持的語法是如何轉換生成__template__函數的。 we...
摘要:前兩篇文章主要說明了的模板系統(tǒng)將模板文件處理后得到的結果函數。生成函數的代碼這個是模板生成過程中最長最復雜的一段,會應用到的分析功能以及動態(tài)編譯功能。參數都是一個,表示還未解析的模板內容。 前兩篇文章主要說明了web.py的模板系統(tǒng)將模板文件處理后得到的結果:__template__()函數。本文主要講述模板文件是如何變成__template__()函數的。 Render和frende...
摘要:前言在文章基于環(huán)境搭建框架方法介紹中介紹了客戶端和服務器的交互過程,服務器接收客戶端的請求后,由應用服務器對瀏覽器的請求進行處理,將生成的響應傳遞給服務器,再由服務器返回給客戶端。 前言 在文章《基于Linux環(huán)境搭建Nginx+uWSGI+Python框架方法介紹》中介紹了客戶端和Web服務器的交互過程,Web服務器接收客戶端的請求后,由Web應用服務器對瀏覽器的請求進行處理,將生成...
摘要:是應用性能管理監(jiān)控解決方案提供商。目錄是列出的命令腳本所在目錄。包含文件如下的函數是命令執(zhí)行的入口。而對于硬件信息的檢測則由進行。文檔地址源碼仔細看下去,太復雜了。下一篇再分析一個請求到結束探針工作的完整過程吧。 Newrelic 是APM(Application Performance Management)(應用性能管理/監(jiān)控)解決方案提供商。項目中,通常用它來追蹤應用的性能。最近...
摘要:本文主要分析的是庫的這個模塊中的代碼。將結果轉換成一個迭代器。函數函數的定義如下位置位置位置該函數的參數中就是,是路由映射表則是,是本次請求路徑。位置,如果是其他情況,比如直接指定一個類對象作為處理對象。 本文主要分析的是web.py庫的application.py這個模塊中的代碼??偟膩碚f,這個模塊主要實現了WSGI兼容的接口,以便應用程序能夠被WSGI應用服務器調用。WSGI是We...
閱讀 2393·2021-11-22 14:56
閱讀 10885·2021-09-08 10:45
閱讀 2075·2019-08-30 13:54
閱讀 2923·2019-08-29 16:54
閱讀 2091·2019-08-29 14:20
閱讀 1845·2019-08-29 12:25
閱讀 1911·2019-08-29 12:17
閱讀 1111·2019-08-23 18:29