上一篇文章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模板支持的語法和生成的代碼的對應關係,但願有助於你們理解模板的語法,瞭解每種語法的用途,避免踩坑。