Python 模板引擎
有没有人能帮我入门,教我怎么写一个Python模板引擎?我刚开始学Python,已经写了一个简单的MVC框架,并在自己的轻量级WSGI服务器上运行。
我写了一个脚本,可以找到并替换键值对:
(当然,这不是我脚本的实际结构或实现方式,这只是一个例子)
from string import Template
html = '<html>\n'
html += ' <head>\n'
html += ' <title>This is so Cool : In Controller HTML</title>\n'
html += ' </head>\n'
html += ' <body>\n'
html += ' Home | <a href="/hi">Hi ${name}</a>\n'
html += ' </body>\n'
html += '<html>'
Template(html).safe_substitute(dict(name = 'Arturo'))
我接下来的目标是实现自定义语句、修饰符、函数等等(比如'for'循环),但我不太确定是否需要使用我不知道的其他模块。我想过使用正则表达式,但感觉那样做效率不高。
任何帮助都非常感谢,我相信这对其他人也会有用。
谢谢!
3 个回答
1
好吧,当我决定像你一样尝试的时候,测试驱动开发(TDD)总是个不错的选择。
那么,为什么不试试呢?
比如,创建一个叫做 jturo_template.py 的文件,然后写:
import re import unittest class JTuroTemplate(object): u"""JTuro's template engine core class""" variable_regex = r'\$\{((.*)(%s)([^}]*))*\}' def __init__(self, string): self.string = string def __repr__(self): pieces = self.string.split() if len(pieces) > 3: head = "%s ..." % " ".join(pieces[:3]) else: head = " ".join(pieces) return u'<JTuroTemplate: "%s">' % (head) def render(self, context): new = unicode(self.string) for key, value in context.items(): variable_name = re.escape(key) regex = re.compile(self.variable_regex % variable_name) for match in regex.findall(new): if match[0]: replacement = match[0].replace(key, repr(value)) new = new.replace('${%s}' % match[0], unicode(eval(replacement))) return new class TestJTuroTemplate(unittest.TestCase): def test_repr(self): "a instance will be nicely represented" jt = JTuroTemplate('my template') self.assertEquals(repr(jt), '<JTuroTemplate: "my template">') def test_repr_truncated(self): "the python representation is truncated after 3 words" jt = JTuroTemplate('such a long string template') self.assertEquals(repr(jt), '<JTuroTemplate: "such a long ...">') def test_solves_simple_variables(self): "it solves simple variables" jt = JTuroTemplate('my variable is ${var} == 4') self.assertEquals(jt.render({'var': '4'}), 'my variable is 4 == 4') def test_solves_variables_with_python_code(self): "it solves variables with python code" jt = JTuroTemplate('my variable is ${var + var} == 44') self.assertEquals(jt.render({'var': '4'}), 'my variable is 44 == 44') if __name__ == '__main__': unittest.main()
抱歉发了这么长的帖子,但我觉得你可以试试这个工作流程:
- 先写一个会失败的测试
- 运行它,看看它失败了
- 写代码让这个测试通过
- 再运行一次,看看它通过了
4
好吧,正如你所说,你是个Python新手,而你之所以从头开始写一个新的MVC框架和模板引擎,纯粹是为了学习,这样的话,我觉得你不需要太在意性能。
不过,如果你打算把它用在实际项目中,那就应该考虑使用一些已经存在的模板引擎,比如jinja2、mako、genshi等等。
无论如何,如果你想玩玩的话,这里有一个轻量级的Python网页框架的好例子:http://github.com/breily/juno
还有一个快速的模板引擎可以看看:http://github.com/eklitzke/spitfire
祝你编程愉快!