内容简介:这两天简单研究了一下web.py框架,发现比较有意思的就是template模板引擎的实现了,所以简单研究了一下基本原理。我们先看一个web.py的模板例子。我有这样一个模板文件:
这两天简单研究了一下web.py框架,发现比较有意思的就是template模板引擎的实现了,所以简单研究了一下基本原理。
例子
我们先看一个web.py的模板例子。
我有这样一个模板文件:
$def with (words) <!DOCTYPE html> <html lang="en"> <head> <title>web-py</title> $:render.header() </head> <body> <h1>$words</h1> <ul> $for i in range(0, 10): <li>$i</li> </ul> </body> </html>
这是一个HTML文件,凡是动态内容,均需要以$开头标识出来,以便模板引擎解析替换。
- $def with (words):这是定义了 python 要传进来的动态参数,在<h1>$words</h1>中渲染。
- $:render.header():这是调用了render对象的header()方法,作用是渲染另外一个模板文件。
- $for i in range(0,10):通过循环制作一个列表。
按照简单理解,python只需要把模板文件读进内存,然后用正则去替换一下$words这样的东西就好了。但是复杂就是,模板引擎还允许执行python代码,比如调用header()函数,for循环,这种用正则怎么可能处理的了呢?所以,模板引擎的实现思路就特别重要了。
模板 -> 代码
如何让模板引擎可以执行Python代码呢?我们不如先看看web.py是如何渲染的。
web.py对上述模板文件经过一番处理,得到的实际上就是一段python代码:
# coding: utf-8 def __template__ (words): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_(['\n']) extend_(['<!DOCTYPE html>\n']) extend_(['<html lang="en">\n']) extend_(['<head>\n']) extend_([' <title>web-py</title>\n']) extend_([' ', escape_(render.header(), False), '\n']) extend_(['</head>\n']) extend_(['<body>\n']) extend_([' <h1>', escape_(words, True), '</h1>\n']) extend_([' <ul>\n']) for i in loop.setup(range(0, 10)): extend_([' ', '<li>', escape_(i, True), '</li>\n']) extend_([' </ul>\n']) extend_(['</body>\n']) extend_(['</html>\n']) return self
观察可以发现,这个函数就是HTML模板文件的python实现:
- 模板的入参变成了__template__函数的入参
- 文本的HTML代码变成了python不断extend_追加字符串的过程
- 嵌套渲染其他模板变成了header()函数调用,结果又extend_到最终结果中去
- 循环也变成了真的python代码循环
实际上,模板引擎要做的就是对模板文件进行语法解析,把普通文本转换为extend_(xxx),把python表达式原样的挪过来,最后拼成一个可执行的python函数。
当然,这个解析过程涉及到语法解析的知识,我个人不擅长,所以不展开研究了。
编译代码
当前我们通过语法解析,生成了上述的一段python代码(是一段文本而已),这段代码做的唯一的事情就是定义了一个__template__函数。
现在我们要用这个函数来渲染模板得到最终的HTML,所以需要执行这段代码,得到真正的python可执行函数。
我把这个事情简化一下,现在我们要做的事情是先编译这段代码:
# -*- coding: utf-8 -*- # 纯文本代码 code = """ def f(x): return x * x """ # 编译文本代码, 生成AST抽象语法树 ast = compile(code, '', 'exec')
code中的文本代码,被编译成了AST抽象语法表达树,但是当前还没有被执行。
执行代码
如果code中的代码放在一个.py文件中,我们知道直接调用f()就可以了,但是现在code只是一段字符串,这时候如何执行代码呢?
这时候我们需要用到exec方法,它可以动态执行一段代码,同时允许单独指定代码执行的上下文环境:
# 执行代码
global_env = {}
exec(ast, global_env)
exec第一个参数是代码,第二个参数是所处的全局环境,第三个代码是所处的局部环境。
我们知道,当在全局作用域定义函数的时候,函数会被保存到globals()中;在局部作用域(比如某个函数内)定义函数的时候,函数会被保存到locals()中。
所以我们定义一个空字典global_env当做代码执行的全局环境,那么f函数就会保存到global_env中。
调用函数
现在,我们可以从global_env中取出f函数,直接调用它即可:
# 函数f就被定义到global_env中了, 我们可以取出来可执行函数 f = global_env['f'] # 调用它 result = f(5) print(result)
这就是模板引擎的基本工作原理了,所以模板引擎一般都会把编译好的__template__函数cache起来复用,因为如果每次都去解析模板文件再生成可执行函数的消耗有点大。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 网站模板 | 现代时尚创新创意投资组合HTML5模板设计
- ReportLibrary 报表模板库新增 21 张报表模板,加入报表导出功能!
- ReportLibrary 报表模板库新增 21 张报表模板,加入报表导出功能!
- 工具集核心教程 | 第五篇: 利用Velocity模板引擎生成模板代码
- Word 模板引擎 poi-tl V1.3.0 发布,新增模板语法
- React与Vue模板使用比较(一、vue模板与React JSX比较)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Data Mining
Bing Liu / Springer / 2006-12-28 / USD 59.95
Web mining aims to discover useful information and knowledge from the Web hyperlink structure, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is n......一起来看看 《Web Data Mining》 这本书的介绍吧!