上一篇文章web.py源码分析: 模板(1)说明了web.py的模板的大体工做原理。本文重点讲述web.py模板支持的语法是如何转换生成__template__函数的。html
本章会列出模板内容以及转换以后的__template__()函数的内容,以及必要的文字说明。模板的名称统一是hello.html。web
模板内容segmentfault
hello, world
函数内容app
def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'hello, world\n']) return self
模板内容函数
$def with (name, value=[], *args, **kargs) hello, $name
函数内容oop
def __template__ (name, value=[], *args, **kargs): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'hello, ', escape_(name, True), u'\n']) return self
从生成的函数能够看出,def with语法所生成的就是__template__()函数的参数列表。源码分析
模板内容code
$def with (name, value) $name ${name + value} $(name + value)ing. $name[value].function()
函数内容htm
def __template__ (name, value): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([escape_(name, True), u'\n']) extend_([escape_((name + value), True), u'\n']) extend_([escape_((name + value), True), u'ing.\n']) extend_([escape_(name[value].function(), True), u'\n']) return self
表达式的替换就是执行表达式(表达式对应的代码),获得的结果添加到TemplateResult实例中。对象
模板内容
$def with (name, func) $ name1 = name $ name2 = func()
函数内容
def __template__ (name, func): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend name1 = name name2 = func() return self
其实,转换后就是Python代码里的赋值语句。
模板内容
$def with (name) $name $:name
函数内容
def __template__ (name): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([escape_(name, True), u'\n']) extend_([escape_(name, False), u'\n']) return self
从生成的代码来看,是否使用过滤语法的区别就是传入excape_函数的第二个参数,这个函数其实只是一个字符串处理函数,后续再说。
模板内容
$def with (name, func) $name hello, \ $name \ ! $func(1, 2, 3, 4, 5)
函数内容
def __template__ (name, func): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([escape_(name, True), u'\n']) extend_([u'hello, ']) extend_([escape_(name, True), u' ']) extend_([u'!\n']) extend_([escape_(func(1, 2, 3, 4, 5), True), u'\n']) return self
从结果来看,模板中的断行只是为了避免再结果中插入一个多余的换行符而已。另外,一个表达式的中间是不支持断行的,就好比在模板中不能把func函数的参数列表写成两行。
模板内容
$$
函数内容
def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'$', u'\n']) return self
模板内容
$# comment line hello, world.
函数内容
def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'\n']) extend_([u'hello, world.\n']) return self
模板中注释的行在生成的函数中只有一个换行符。
模板内容
$for i in range(10): I like $i
函数内容
def __template__(): __lineoffset__ = -5 loop = ForLoop() self = TemplateResult(); extend_ = self.extend for i in loop.setup(range(10)): extend_([u'I like ', escape_(i, True), u'\n']) return self
模板中的for循环被转换成了代码中的for循环,并且用上了变量loop(ForLoop对象后续再来看)。
模板内容
$def with (name_list) $while name_list: hello, $name_list.pop()
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'\n']) while name_list: extend_([u'hello, ', escape_(name_list.pop(), True), u'\n']) return self
注意和for循环的区别,没有使用loop变量。
模板内容
$def with (name_list) $for name in name_list: $loop.index $loop.index0 $loop.first $loop.last $loop.odd $loop.even $loop.parity $loop.parent hello, $name $for i in range(10): $for name in name_list: $loop.parent hello, $name
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend for name in loop.setup(name_list): extend_([escape_(loop.index, True), u'\n']) extend_([escape_(loop.index0, True), u'\n']) extend_([escape_(loop.first, True), u'\n']) extend_([escape_(loop.last, True), u'\n']) extend_([escape_(loop.odd, True), u'\n']) extend_([escape_(loop.even, True), u'\n']) extend_([escape_(loop.parity, True), u'\n']) extend_([escape_(loop.parent, True), u'\n']) extend_([u'hello, ', escape_(name, True), u'\n']) extend_([u'\n']) for i in loop.setup(range(10)): for name in loop.setup(name_list): extend_([escape_(loop.parent, True), u'\n']) extend_([u'hello, ', escape_(name, True), u'\n']) return self
这里展现了loop变量的成员,以及嵌套循环的使用。
模板内容
$def with (name_list) $if name_list: $len(name_list) $else: 0
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend if name_list: extend_([escape_(len(name_list), True), u'\n']) else: extend_([u'0\n']) return self
elif语句也支持。
模板内容
$def with (name_list) $def hello(name): hello, $name $def hello_to_all(nlist): $for each in nlist: $hello(each) $hello_to_all(name_list)
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'\n']) __lineoffset__ -= 3 def hello(name): self = TemplateResult(); extend_ = self.extend extend_([u'hello, ', escape_(name, True), u'\n']) extend_([u'\n']) return self __lineoffset__ -= 3 def hello_to_all(nlist): self = TemplateResult(); extend_ = self.extend for each in loop.setup(nlist): extend_([escape_(hello(each), True), u'\n']) extend_([u'\n']) return self extend_([escape_(hello_to_all(name_list), True), u'\n']) return self
模板对函数的支持其实就是定义内部函数而且调用,每一个内部函数的返回结果也都是TemplateResult实例。
模板内容
$def with (name_list) $code: new_list = [x.upper() for x in name_list] def hello(name): return "hello, %s" % (name) more_new_list = [] for each in new_list: more_new_list.append(hello(each)) $hello("everybody") $len(more_new_list)
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend extend_([u'\n']) new_list = [x.upper() for x in name_list] def hello(name): return "hello, %s" % (name) more_new_list = [] for each in new_list: more_new_list.append(hello(each)) extend_([escape_(hello("everybody"), True), u'\n']) extend_([escape_(len(more_new_list), True), u'\n']) return self
code的语法有点复杂,其内部是用来定义原始的Python代码的,有以下几个特色:
code内部定义的函数也是内部函数,在模板的其余地方能够调用,可是不会把结果存放在TemplateResult实例中返回。
code中定义的变量都会做为__template__()函数的局部变量,在模板的其余地方能够调用。
注意,code块中不要使用print语句打印输出(虽然默认已经禁止了)。
模板内容
$def with (name_list) $var title: hi $var title2: "hi" $var name: $name_list[0] $var name2: name_list[0]
函数内容
def __template__ (name_list): __lineoffset__ = -4 loop = ForLoop() self = TemplateResult(); extend_ = self.extend self['title'] = join_(u'hi') self['title2'] = join_(u'"hi"') self['name'] = join_(escape_(name_list[0], True)) self['name2'] = join_(u'name_list[0]') return self
var是用来为模板设置属性的,从生成的代码来看,就是为TemplateResult实例设置属性。上面的模板内容里有一些关键细节:
var name: value中的冒号后面的内容默认是做为字符串处理的,能够不用加引号,若是加了引号,则引号也会做为内容的一部分。
若是要在冒号后面访问一些变量值,须要使用$前缀。
写了这些web.py模板支持的语法和生成的代码的对应关系,但愿有助于你们理解模板的语法,了解每种语法的用途,避免踩坑。