模板引擎实现原理

介绍

本文简单探讨一下django模板引擎是如何是实现的。
例如,我们想将如下html中name变量替换

Topics for {{name}}

得到下面的结果

Topics for owen

实现

既然想替换变量,肯定要先识别变量,我们需要一个类Templite来处理html

text = '

Topics for {{name}}

' context = {'name':'owen'}

初始化参数包括text文本,以及context变量

class Templite(object):
    def __init__(self,text,context):
        text = text
        self.context = context

接下来解析大括号中的内容,首先利用re.split将text按照{{}}进行分割

        import re
        tokens = re.split(r'({{.*?}})',text)

tokens是下面这样的list

['

Topics for ', '{{name}}', '

']

拿到{{name}}了,那怎么替换这个变量呢?
如果接触过namedtuple类,应该知道它的原理是构建python源代码,然后利用exec来执行,这里我们也采用这样的方法
这里用code表示源代码

        code = []

定义函数render_context,并加入到code中,函数有一个context参数用来接收变量,code本身也需要一个result用来存储tokens中的变量,这里还需要" "'x4'\n'*,因为python语法要求缩进和换行

        code.extend(['def render_context(context):','\n',' '*4])
        code.extend(['result = []','\n',' '*4])

下面只需要判断tokens中的变量然后加入到result当中

        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])

处理完成后,需要增加函数返回值

        code.append('return "".join(result)')

再格式化一下code,这样python源代码就完成了

        code = ' '.join(code)

下面执行exec,global_namespace变量作为全局命名空间,可以取出render_context函数

        global_namespace = {}
        exec(code,global_namespace)
        self.render_context = global_namespace['render_context']

最后定义一个render函数,获得执行结果

        def render(self):
            return self.render_context(self.context)

测试

新建Templite对象,执行render函数

tem = Templite(text,context)
print(tem.render())

后续

这里只是实现了模板引擎最简单的功能,条件判断,过滤函数等功能都是在这基础之上实现,可以参考http://aosabook.org/en/500L/a-template-engine.html获得更加详细的说明

你可能感兴趣的:(模板引擎实现原理)