介紹
本文簡(jiǎn)單探討一下django模板引擎是如何是實(shí)現(xiàn)的。
例如攒至,我們想將如下html中name變量替換
<p>Topics for {{name}}</p>
得到下面的結(jié)果
<p>Topics for owen</p>
實(shí)現(xiàn)
既然想替換變量厚者,肯定要先識(shí)別變量,我們需要一個(gè)類Templite來(lái)處理html
text = '<p>Topics for {{name}}</p>'
context = {'name':'owen'}
初始化參數(shù)包括text文本迫吐,以及context變量
class Templite(object):
def __init__(self,text,context):
text = text
self.context = context
接下來(lái)解析大括號(hào)中的內(nèi)容库菲,首先利用re.split將text按照{(diào){}}進(jìn)行分割
import re
tokens = re.split(r'({{.*?}})',text)
tokens是下面這樣的list
['<p>Topics for ', '{{name}}', '</p>']
拿到{{name}}了,那怎么替換這個(gè)變量呢志膀?
如果接觸過(guò)namedtuple類熙宇,應(yīng)該知道它的原理是構(gòu)建python源代碼,然后利用exec來(lái)執(zhí)行溉浙,這里我們也采用這樣的方法
這里用code表示源代碼
code = []
定義函數(shù)render_context烫止,并加入到code中,函數(shù)有一個(gè)context參數(shù)用來(lái)接收變量戳稽,code本身也需要一個(gè)result用來(lái)存儲(chǔ)tokens中的變量馆蠕,這里還需要" "'x4和'\n'*,因?yàn)閜ython語(yǔ)法要求縮進(jìn)和換行
code.extend(['def render_context(context):','\n',' '*4])
code.extend(['result = []','\n',' '*4])
下面只需要判斷tokens中的變量然后加入到result當(dāng)中
for token in tokens:
if token.startswith('{{'):
token = token[2:-2]
code.extend(['%s = context["%s"]'%(token,token),'\n',' '*4])
code.extend(['result.append(%s)'%(token),'\n',' '*4])
else:
code.extend(['result.append("%s")'%(token),'\n',' '*4])
處理完成后广鳍,需要增加函數(shù)返回值
code.append('return "".join(result)')
再格式化一下code荆几,這樣python源代碼就完成了
code = ' '.join(code)
下面執(zhí)行exec,global_namespace變量作為全局命名空間赊时,可以取出render_context函數(shù)
global_namespace = {}
exec(code,global_namespace)
self.render_context = global_namespace['render_context']
最后定義一個(gè)render函數(shù)吨铸,獲得執(zhí)行結(jié)果
def render(self):
return self.render_context(self.context)
測(cè)試
新建Templite對(duì)象,執(zhí)行render函數(shù)
tem = Templite(text,context)
print(tem.render())
后續(xù)
這里只是實(shí)現(xiàn)了模板引擎最簡(jiǎn)單的功能祖秒,條件判斷诞吱,過(guò)濾函數(shù)等功能都是在這基礎(chǔ)之上實(shí)現(xiàn),可以參考http://aosabook.org/en/500L/a-template-engine.html獲得更加詳細(xì)的說(shuō)明