web.py源碼分析: 模板(2)

上一篇文章web.py源碼分析: 模板(1)說明了web.py的模板的大體工做原理。本文重點講述web.py模板支持的語法是如何轉換生成__template__函數的。html

web.py模板語法和__template__()函數的對應關係

本章會列出模板內容以及轉換以後的__template__()函數的內容,以及必要的文字說明。模板的名稱統一是hello.htmlweb

純字符串

模板內容segmentfault

hello, world

函數內容app

def __template__():
    __lineoffset__ = -5
    loop = ForLoop()
    self = TemplateResult(); extend_ = self.extend
    extend_([u'hello, world\n'])

    return self

def with

模板內容函數

$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_函數的第二個參數,這個函數其實只是一個字符串處理函數,後續再說。

模板代碼斷行(newline suppression)

模板內容

$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循環

模板內容

$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對象後續再來看)。

while循環

模板內容

$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變量。

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變量的成員,以及嵌套循環的使用。

if-else

模板內容

$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實例。

code

模板內容

$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語句打印輸出(雖然默認已經禁止了)。

var

模板內容

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

相關文章
相關標籤/搜索