當前位置:
首頁 > 知識 > 252 行代碼搞定 Python 模板實現

252 行代碼搞定 Python 模板實現

本文翻譯自 500 lines or less 系列文章,作者 Ned Batchelder,譯者 mageelen。

譯文鏈接:http://mageelen.github.io/2016/04/16/500linesorless/Atemplate_engine/index.html

Ned Batchelder 是一名非常有經驗的工程師,目前就職於 edX,主要從事開源軟體推廣工作,他同時也是 coverage.py 的維護者,Boston Python 的組織者,並參與多個 PyCons,甚至還接受過美國的白宮晚宴,他的博客地址為http://nedbatchelder.com。

簡介

大多數的程序都是由多數邏輯計算和少量的文字處理構成的,程序語言一般也以邏輯計算為中心,但是有些時候我們也需要進行大量的文字處理,這就需要有個一比較好的文字處理工具。本次設計的目的就是為了解決文字處理這一方面的需求,在這一章,我們將設計一個基於模板的文字處理引擎。

文字處理大量被應用在互聯網程序設計中,比如生成共瀏覽器顯示的 HTML 網頁,實際上現在的 HTML 網頁已經很少是完全的靜態網頁,一般都是含有一部分動態數據,比如網頁中的用戶名,產品列表,朋友的更新,新聞的更新等等。

與此同時,每一個 HTML 頁面還含有大量的靜態文本,這樣多大幾 K 的動態數據和靜態數據混合的文本就成為程序處理的一個難點,另外 HTML 裡面的靜態文本一般由前端工程師完成,動態數據則由後端生成,如何更好的使前後端協調工作?

為了解決這方面的難題,我們假設需要如下的一個靜態頁面:

在上述頁面里,用戶名就屬於動態數據,同樣的還有產品名字和產品價格,另外還有產品數量沒有添加到頁面,有可能還有更多或更少的產品需要顯示。

為了生成這樣的頁面,比較簡單的方法是將所有的字元添加到我們的程序代碼裡面,通過在代碼中動態生成相應的結果字元串,而對於產品的顯示,我們可能需要通過循環來適應不同的產品數量。

這種生成方式的程序代碼如下:

上述代碼是可以工作的,但是這裡面有很多問題,因為 HTML 直接包含在我們的代碼中,並且被拆分成很多部分,這樣就失去了代碼的邏輯性。另外,如果前端工程師需要就該 HTML 代碼,他不得不去研究在 Python 裡面這部分代碼是如何工作的,假設 HTML 的代碼有幾百上千個,那基本上 HTML 代碼是無法修改的。

模板

一個比較好的方法是通過 HTML 頁面模板的方式實現我們需要的功能,這種情況下,多數的靜態 HTML 代碼包含在模板中,少量的動態數據通過特定格式插入到模板中,比如上述頁面就可以轉換成如下的模板文件:

在上面的模板中,我們主要是完成 HTML 的設計,少量的邏輯代碼嵌入其中。

在模板中用到的大量的靜態文本與程序設計中的模式並不相同,比如,在 Python 中,大量的代碼都是可執行的,如果需要靜態文本,我們需要加上引號:

當 Python 讀取源文件的時候,Python 會把像 這樣的文本翻譯為指令,而引號中的像 ``"Hello, world"的文本則代表靜態的文本。這就是一般的程序執行模式:大量的邏輯代碼和少量的靜態文本,靜態文本通過特殊的方式標示。

而模板語言則剛好相反,大量的文本都屬於靜態文本,只含有少量的動態可執行部分:

模板裡面的文本一般都是直接顯示到 HTML 的結果頁面,直到遇到 這樣的需要轉換為動態數據的標誌,之後 user_name 將會被作為變數輸出到結果。

模板語言參考了類似於 這樣的格式化函數,從而實現了動態數據的添加。另外模板將這種思想進行了豐富,實現了對於條件和循環等多種標籤的支持。

之所以把這些文件稱之為模板是因為通過這些文件可以生成有統一格式的各種文件。

為了在我們程序中實現 HTML 模板的功能,我們需要一個模板引擎,這個引擎接受描述數據樣式的模板數據和將要插入到模板中顯示的動態數據,引擎主要完成對模板的解析,將模板中的動態數據標籤用動態數據結果進行替換的功能。

另外,這裡的模板不僅僅局限於生成 HTML 頁面,實際上任何純文本的結果都可以通過這個模板引擎實現,例如生成純文本的電子郵件。

支持的語法

不同的模板支持各種不同的語法,我們的模板語法是基於 Django 的模板系統實現的。另外,因為我們引擎是通過 Python 實現的,因此在語法裡面會有一些 Python 的概念,下面就是我們將要設計的模板支持的語法的一個匯總:

數據的引用通過雙大括弧 實現:

數據將在模板渲染(render) 的過程進行轉換,詳細細節後面會有提及。

模板引擎同樣支持對數據元素的的提取,在 Python 中,不同的數據類型有不同的提取方式:

但是在我們的模板設計中,所有的操作都是通過 實現:

點號會直接訪問對象的屬性或字典的值,如果結果是一個可調用的函數,那麼將會直接對結果進行調用。這與 Python 代碼是有區別的。這主要是為了簡化模板的設計,採用這種語法的一個簡單示例:

對於一個對象,點號可以級聯使用,比如對象的屬性是另外一個對象,可以通過級聯的方式進行更深層的訪問。

在模板中還可以調用 filter 功能,該功能允許更改數據轉換的方式,同樣也可以級聯:

有些時候,我們還需要少量的邏輯代碼,比如條件語句:

以及循環語句:

最後,我們可能還需要對模板進行必要的注釋:

實現方法

概括的說,我們的模板引擎需要實現兩個主要功能:分析模板和渲染模板。

渲染模板主要任務:

管理動態數據內容

執行邏輯單元代碼塊

實現點號數據訪問和 filter 的執行

這裡面的關鍵問題是分析模板的結果如何傳遞到模板渲染模塊。什麼樣的分析結果可以被直接轉換?有翻譯(interpretation) 和編譯(compilation) 兩種選擇。

翻譯模式,分析模塊生成一個代表模板結構的數據結構。渲染模塊遍歷整個數據結構,將需要翻譯的部分進行替換,Django 的模板引擎就是採用的這種方法。

編譯模式,分析模塊直接產生可執行代碼,渲染模塊執行代碼得到結果,Jinja2Mako就是採用的這種方法。

我們今天將要採用編譯模式實現我們的模板引擎:我們將會將模板編譯為 Python 代碼,執行代碼,最後得到結果。

這裡所描述的代碼引擎實際上是 的一部分,主要用來產生 HTML 報告。在 裡面,通過反覆調用少量的模板生成很多類似的結構的文件。總的來說,如果把模板編譯成 Python 代碼,程序運行會更有效率。因為雖然編譯需要很長時間,但在使用過程中只需要編譯一次,而運行次數則不受限制,這樣可以實現一次編譯,多次運行,顯著的提高了運行效率。

雖然把模板編譯為可執行代碼有點麻煩,但也不至於你想的那樣糟糕。而且任何的碼農後會覺得編寫一個可以生成程序的程序更有意思。

我們的模板引擎實際上是一個代碼生成技術的一個例子。代碼生成通過各種靈活軟體及編譯器直接生成複雜的可執行代碼。

如果每次編譯模板只運行幾次,或模板需要經常更改,那麼推薦使用翻譯模式,那樣將會得到更好的效率。

編譯到 Python

在開始之前,讓我們先來看一下我們預期要達到的一個編譯結果,首先再來回顧一下我們的模板:

我們的模板引擎會分析模板,並將結果轉換為可執行的 Python 代碼,這裡的代碼可能會有一些彆扭,因為我們用了一些代碼優化,以便可以得到更好的運行效率(下面代碼為方便閱讀已經修改):

每一個模板都會被轉換成一個 函數,函數接收一個名稱為 的字典。函數內部首先對字典進行解包,然後將 轉化為本地局部變數,因為轉換之後可以更快的進行多次調用。所有本地局部變數冠以 前綴。

函數的運行結果是一個字元串。最快速的通過字元串片段生成字元串的方式就是先建立一個字元串列表,然後通過 join 函數生成結果字元串。 就是這個字元串列表,因為我們還需要對 列表進行 和 操作,於是我們把這兩個方法也本地化成 和 ,這樣可以得到更高效率的重複調用。我們最後還將 函數本地化了,因為這個函數也需要多次調用。

雖然這樣的本地化的方式在 Python 中並不常用,但是因為節省了函數查找的時間,可以得到更好的執行效率。

這是一個比較簡單的優化技巧:通過非常規編程得到更好的運行效率,這些優化雖然不宜讀,可能還有些複雜,但是卻對程序運行的效率有明顯改善。但即使如此,有些技巧也勿濫用,畢竟它影響了程序的可讀性。

一旦我們定義好這些局部函數,我們就可以對他們進行調用,比如通過 或 對 result 列表進行操作。

同時使用 和 可能有點混亂,但是我們的目標是儘可能高的執行效率,通過 extend 可以生成一個性的列表,這個列表可以再次被傳遞到 extend 以便執行下次循環。

中的語句會被執行,轉換成字元串,添加到結果,而點號會被 函數單獨處理,因為這裡面點號可能有多種含義,可能是字典元素,或是對象屬性,也可能是可執行方法。

邏輯代碼塊 和 被轉換成 Python 的條件和循環語句。其中的表達式會變成 和 語句中的表達式,而中間直到 將會轉換為 或 的代碼塊.

引擎的編寫

前面我們已經了解了模板引擎的實現方法,現在我們開始著手實現這個引擎。

Templite 類

模板引擎的核心就是這個 Templite 類(Template Lite)

Templite 有一個小的介面。一旦你構造了這樣一個類,後面就可以通過調用 方法實現對特定 (內容字典) 的渲染:

這裡,我們在例化的時候已經將模板傳入,之後我們就可以直接對模板進行一次編譯,在之後就可以通過 方法對模板進行多次調用。

構造函數接受一個字典參數作為內容的初始化,他們直接被存儲在類內部,在後期調用 方法的時候可以直接引用。同樣,一些會用到的函數或常量也可以在這裡輸入,比如之前的 函數。

再開始討論 Temlite 類實現之前,我們先來看一下這樣一個類:CodeBuilder。

CodeBuilder

我們編寫模板引擎的主要工作就是模板解析和產生必要的 Python 代碼。為了幫助我們更好的產生 Python 代碼,我們需要一個 的類,這個類主要負責代碼的生成:添加代碼,管理縮進以及返回最後的編譯結果。

一個 實例完成一個 Python 方法的構建,雖然在我們模板引擎中只需要一個函數,但是為了更好的抽象,降低模塊耦合,我們的 將不僅僅局限於生成一個函數。

雖然我們可能直到最後才會知道我們的結果是什麼樣子,我們還是把這部分拿到前面來說一下。

主要有兩個元素,一個是用於保存代碼的字元串列表,另外一個是標示當前的縮進級別。

下面我們來看一下我們需要的介面和具體實現。

方法將添加一個新的代碼行,縮進將自動添加

和 增加和減少縮進級別的函數:

通過另一個 CodeBuilder 管理,這裡先預留一個位置,後面再繼續完善, 主要由代碼字元列表構成,但同時也支持對其他代碼塊的引用。

用於產生所有代碼,它將遍歷 列表,而對於 中的 sections,它也會進行遞歸調用:

通過執行代碼迭代生成結果:

在這裡面用到了 Python 一個非常有特色的功能, 函數,該函數可以將字元串作為代碼執行,函數的第二個參數是一個用於收集代碼定義全局變數的一個字典,比如:

輸出結果:

雖然我們只需要 CodeBuilder 產生一個函數,但是實際 CodeBuilder 的使用並不局限於一個函數,它實際是一個更為通用的類。

CodeBuilder 可以產生 Python 代碼,但是並不依賴於我們的模板,比如我們要產生三個函數,那麼 實際就可以產生含有三個函數的字典,這是一種非常實用的程序設計方法。

下面我們回歸 Templite 類,看一下如何去實現這樣一個類

Templite 類的實現

就像之前我們所講的一樣,我們的主要任務在於實現模板發解析和渲染。

編譯(解析 Compiling)

這部分工作需要完成模板代碼到 python 代碼的轉換,我們先嘗試寫一下構造器:

注意,我們使用 作為一個參數, 代表可以傳入任意數量的參數,所有的參數都將打包在一個元組裡面,元組名稱為 。這稱之為參數解包,比如我們可以通過如下方式進行調用:

內容參數作為一個元組傳入,我們通過對元組進行遍歷,對其依次進行處理,在構造器中我們聲明了一個 的字典, python 中對重名情況直接使用最近的定義。

同樣,為了更有效的編譯函數,我們將 中的變數也本地化了,我們同樣還需要對模板中的變數進行整理,於是我們定義如下兩個元素:

之後我們會講到如何去運用這些變數。首先,我們需要用 CodeBuilder 類去產生我們編譯函數的定義:

這裡,我們構造一個 CodeBuilder 類,添加函數名稱為 ,以及函數的兩個參數:數據字典 和實現點號屬性獲取的函數

這裡的數據字典包括傳入 Templite 例化的數據字典和用於渲染的數據字典。是整個可以獲取的數據的一個集合。

而作為代碼生成工具的 CodeBuilder 並不關心自己內部是什麼代碼,這樣的設計使 CodeBuilder 更為簡潔和易於實現。

我們還創建了一個名稱為 的代碼段,後面我們會把我們的變數放到這個段裡面,該代碼段為我們預留了一個後面添加代碼的空間。

另外的四行分別添加了結果列表 的定義,局部函數的定義,正如之前說過的,這都是為了提升運行效率而添加的變數。

接下來,我們定義一個用於緩衝輸出的內部函數:

因為我們需要添加很多 code 到 CodeBuilder,所以我們選擇將這種重複的添加合併到一個擴展函數,這是另外的一種優化,為了實現這種優化,我們添加一個緩衝函數。

函數保存我們將要寫入的 code,而在我們處理模板的時候,我們會往 列表裡添加字元串,直到遇到其他要處理的點,我們再將緩衝的字元寫入生成函數,要處理的點包括代碼段,或者循環判斷語句的開始等標誌。

函數是一個閉包,裡面的變數包括 和 。這樣我們以後調用的時候就不需要指定寫入那個 code,從那個變數讀取數據了。

在函數里,如果只是一個字元串,那麼調用 appendresult 函數,如果是字元串列表,則調用 extendresult 函數。

擁有這個函數之後,後面需要添加代碼的時候只需要往 裡面添加就可以了,最後調用一次 即可完成代碼到 CodeBuilder 中的添加。

比如我們有一行代碼需要添加,即可採用下面的形式:

後面會添加如下代碼到 CodeBuilder

也就是將字元串 添加到模板的渲染。太多層的抽象實際很難保持一致性。編譯器使用 append_result( hello )`` 到編譯結果中。

讓我們再回到 Templite 類,在我們進行解析的時候,我們需要判斷模板

能夠正確的嵌套,這就需要一個 來保存字元串堆棧:

比如在遇到 標籤的時候,我們就需要將 if 進行壓棧,當遇到 的時候,需要將之前的的 if 出棧,如果解析完模板的時候,棧內還有數據,就說明模板沒有正確的使用。

現在開始做解析模塊。首先通過使用正則表達式將模板文本進行分組。正則表達式是比較煩人的: 正則表達式主要通過簡單的符號完成對字元串的模式匹配。因為正則表達式的執行是通過 C 完成的,因此有很高的效率,但是最初接觸時比較複雜難懂,比如:

看起來是不是相當複雜?我們來簡單解釋一下:

函數主要通過正則表達式完成對字元串的分組,而我們的正則表達式內部也含有分組信息( ),因此函數將返回對字元串分組後的結果,這裡的正則主要匹配語法標籤,所以最終字元串將在還有語法標籤的地方被分割,並且相應的語法標籤也會被返回。

正則表達式里的 表示即使在一個新行也需要有一個點號(?),後面的分組有三種不同的選項: 會匹配一個標籤, 會匹配一個語句表達式, 會匹配一個注釋。這幾個選項裡面,我們用 來匹配任意數目的任意字元,不過用了非貪婪匹配,因此它將只匹配最少數目的字元。

的輸出結果是一個字元串列表,如果模板是如下的字元:

將會返回如下的結果

一旦將模板進行了分組,我們就可以對結果進行遍歷,對每種不同的類型進行不同的處理。

比如對各種符號的編譯可以採用如下的形式:

在遍歷的時候,我們需要判斷每個標誌的類型,實際我們只需要判斷前兩個字元。而對於注釋的標誌處理最為簡單,我們只需要簡單的跳過即可:

對於 這樣的表達式,需要將兩邊的括弧刪除,刪減表達式兩邊的空格,最後將表達式傳入到 :

方法會將模板中的表達式編譯成 Python 語句,後面會具體降到這個方法的實現。再之後通過 函數將編譯後的表達式轉換為字元串添加到我們的結果中。

後面一個條件判斷最為複雜: 語法標籤的處理。它們將會被編譯成 Python 中的代碼段。在操作之前,首先需要將之前的結果保存,之後需要從標籤中抽取必要的關鍵詞進行處理:

目前支持的語法標籤主要包含三種結構: , 和 . 我們來看看對於 的處理:

這裡 後面必須有一個表達式,因此 的長度應該為 2(譯者:難道不會有空格??),如果長度不正確,那麼將會產生一個語法錯誤。之後會對 語句進行壓棧處理以便後面檢測是否有相應的 結束標籤。 後面的判斷語句通過 編譯,並添加 代碼後添加到結果,最後增加一級縮進。

第二種標籤類型是 , 它將被編譯為 Python 的 for 語句:

這一步我們檢查了模板的語法,並且將 標籤壓棧。 方法主要檢測變數的語法,並將變數加入我們的變數集。我們通過這種方式來實現編譯過程中變數的統計。後面我們會對函數做一個統計,並將變數集合添加在裡面。為實現這一操作,我們需要將遇到的所有變數添加到 ,而對於循環中定義的變數,需要添加到 .

在這之後,我們添加了一個 代碼段。而模板中的變數通過加 前綴被轉化為 python 中的變數,這樣可以防止模板中變數與之衝突。通過使用 將模板中的表達式編譯成 Python 中的表達式。

最後我們還需要處理 標籤;實際對 和 來說都是一樣的:主要完成對相應代碼段的減少縮進功能。

注意,這裡結束標籤最重要的功能就是結束函數代碼塊,減少縮進。其他的都是一些語法檢查,這種操作在翻譯模式一般都是沒有的。

說到錯誤處理,如果標籤不是 , 或者 ,那麼程序就無法處理,應該拋出一個異常:

在處理完三種不同的特殊標籤 , 和 之後。剩下的應該就是普通的文本內容。我們需要將這些文本添加到緩衝輸出,通過 方法將其轉換為 Python 中的字元串:

如果不使用 方法,那麼在編譯的結果中就會變成:

相應的我們需要如下的形式:

函數會自動給引用的文本添加引號,另外還會添加必要的轉意符號:

另外我們首先檢測了字元是否為空 , 因為我們沒必要將空字元也添加到輸出。空的 一般出現在兩個特殊的語法符號中間,這裡的空字元檢測可以避免向最終的結果添加 這樣沒有用的代碼。

上面的代碼基本完成了對模板中語法標籤的遍歷處理。當遍歷結束時,模板中所有的代碼都被處理。在最後,我們還需要進行一個檢測:如果 非空,說明模板中有未閉合的標籤。最後我們再將所有的結果寫入編譯結果。

還記得嗎,我們在最開始創建了一個代碼段。它的作用是為了將模板中的代碼抽取並轉換到 Python 本地變數。 現在我們對整個模板都已經遍歷處理,我們也得到了模板中所有的變數,因此我們可以開始著手處理這些變數。

在這之前,我們來看看我們需要處理變數名。先看看我們之前定義的模板:

這裡面有兩個變數 和 。這些變數在模板遍歷後都會放到 集合中。但是在這裡我們只需要對 進行處理,因為 是在 for 循環中定義的。

存儲了模板中的所有變數,而 則存儲了循環中的變數,因為循環中的變數會在循環的時候進行定義,因此我們這裡只需要定義在 卻不在 的變數:

這裡每一個變數都會從 數據字典中獲得相應的值。

現在我們基本上已經完成了對模板的編譯。最後我們還需要將函數結果添加到 列表中,因此最後還需要添加如下代碼到我們的代碼生成器:

到這裡我們已經實現了對模板到 python 代碼的編譯,編譯結果需要從代碼生成器 中獲得。可以通過 方法直接返回。還記得嗎,我們需要的代碼只是一個函數(函數以 開頭), 因此編譯結果是得到這樣一個 函數而不是函數的執行結果。

的返回結果是一個字典,我們從中取出 函數,並將它保存為 類的一個方法。

現在 已經是一個可以調用的 Python 函數,我們後面渲染模板的時候會用到這個函數。

表達式編譯

到現在我們還不能看到實際的編譯結果,因為有個一重要的方法 還沒有實現。這個方法可以將模板中的表達式編譯成 python 中的表達式。有時候模板中的表達式會比較簡單,只是一個單獨的名字,比如:

有時候會相當複雜,包含一系列的屬性和過濾器(filters):

需要對上面各種情況做出處理,實際複雜的表達式也是由簡單的表達式組合而成的,跟一般語言一樣,這裡用到了遞歸處理,完整的表達式通過 分割,表達式內部還有點號 分割。因此在函數定義的時候我們採用可遞歸的形式:

函數內部首先考慮 分割,如果有 ,就按照 分割成多個表達式,然後對第一個元素進行遞歸處理:

而後面的則是一系列的函數名。第一個表達式作為參數傳遞到後面的這些函數中去,所有的函數也會被添加到 集合中以便例化

如果沒有 ,那麼可能有點號 操作,那麼首先將開頭的表達式進行遞歸處理,後面再依次處理點好之後的表達式。

為了理解點號是怎麼編譯的,我們來回顧一下,在模板中 可能代表 , 甚至 。這種不確定性意味著我們需要在執行的過程中依次對其進行嘗試,而不能再編譯時就去定義。因此我們把這部分編譯為一個函數調用 ,這個函數將會對各種情形進行遍歷並返回最終的結果值。

函數已經傳遞到我們編譯的結果函數中去了。它的實現稍後就會講到。

最後要處理的就是沒有 和 的部分,這種情況下,這些就是簡單的變數名,我們只需要將他們添加到 集合,然後同帶前綴的名字去獲取即可:

輔助函數

在編譯過程中,我們還用到了幾個輔助函數。 函數將錯誤輸出並拋出異常:

方法對變數進行驗證,並將他們添加到變數集合中,我們利用一個正則表達式去驗證變數名是否有效:

到這裡,編譯代碼已經完成!

渲染

剩下的工作就是編寫渲染代碼。既然我們已經將模板編譯為 Python 代碼,這裡工作量就大大減少了。這部分主要準備數據字典,並調用編譯的 python 代碼即可:

記住,在我們例化 的時候就已經初始化了一個數據字典。這裡我們將他複製,並將其與新的字典進行合併。拷貝的目的在於使各次的渲染數據獨立,而合併則可以將字典簡化為一個,有利於初始數據和新數據的統一。

另外,寫入到 render 的數據字典可能覆蓋例化 時的初始值,但實際上例化時的字典有全局的一些東西,比如過濾器定義或者常量定義,而傳入到 中的數據一般是特殊數據。

最後我們只需要調用 方法,第一個參數是數據字典,第二個參數是 的實現函數,是每次都相同的自定義函數,實現如下:

在編譯過程中,模板中像 的代碼會被編譯為 ``do_dots(x, y , z ). 在函數中會對各個名字進行遍歷,每一次都會先嘗試獲取屬性值,如果失敗,在嘗試作為字典值獲取。這樣使得模板語言更加靈活。在每次遍歷時還會檢測結果是不是可以調用的函數,如果可以調用就會對函數進行調用,並返回結果。

這裡,函數的參數列表定義為 ,這樣就可以獲得任意數目的參數,這同樣使模板設計更為靈活。

注意,在調用 的時候,我們傳進了一個函數,一個固定的函數。可以認為這個是模板編譯的一部分,我們可以直接將其編譯到模板,但是這樣每個模板都需要一段相同的代碼。將這部分代碼提取出來會使得編譯結果更加簡單。

測試

假設需要對整個代碼進行詳盡的測試以及邊緣測試,那麼代碼量可能超過 500 行,現在模板引擎只有 252 行代碼,測試代碼就有 275 行。測試代碼的數量多於正是代碼是個比較好的的測試代碼。

未涉及的地方

完整的代碼引擎將會實現更多的功能,為了精簡代碼,我們省略了如下的功能:

模板繼承和包含

自定義標籤

自動轉義

參數過濾器

例如 和 的複雜邏輯

多於一個變數的循環

空白符控制

即便如此,我們的模板引擎也十分有用。實際上這個引擎被用在 中以生成 HTML 報告。

總結

通過 252 行代碼,我們實現了一個簡單的模板引擎,雖然實際引擎需要更多功能,但是這其中包含了很多基本思想:將模板編譯為 python 代碼,然後執行代碼得到最終結果。

題圖:pexels,CC0 授權。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python 的精彩文章:

Python版演算法專題 二叉樹的深度優先遍歷
手把手教你用Python和Scikit-learn 實現垃圾郵件過濾
Python 為何能坐穩 AI 時代頭牌語言
如果十年前擁有這些技術,你可能比馬雲還要富:python3開發網路爬蟲(一)

TAG:Python |

您可能感興趣

Photoshop製作3D立體感主題的APP展示模板
Office 365 應用開發的.NET Core 模板庫
「Shopify模板」Shopify模板編輯&Shopify模板代碼更改教程
使用Unity 2018.1項目模板功能
Lens Studio 2.1版上線,增新模板和初學指南
thinkphp5連載模板-包含文件
精裝時尚,她可以成為你的時尚之路模板 | HARDcANDY KOL 100輯 · 24號人物 AvaFoo
TensorFlow 項目模板架構最佳實踐
2019就靠這套簡歷模板拿offer了!
MyBatis中Dao層、Service層以及xml文件的CRUD模板
WordPress分類怎麼用不同的模板?Custom Category Templates試試
Django 模板
2篇College Essays經典模板,琢磨下如何出彩的吧!
Android Studio項目模板全面解析
flask中jinjia2模板引擎使用詳解2
2018最新國產Office終於有蘋果系統版的了,還有辦公模板
快速開啟你的第一個項目:TensorFlow項目架構模板
簡記siteserver遠程模板下載Getshell漏洞
CrossFit訓練計劃制定的理論模板
PyGame Zero: 無需模板的遊戲開發