python筆記-文字處理(第三天)
python筆記-文字處理(第三天)
宣告:本人是每天學習賴明星《python linux系統管理與自動化運維》一書後,整理成自己的筆記,供學習和分享使用,如有需要,請購買作者正版書,謝謝
1、字串常量
1.1、定義字串
python不區分字元和字串,所以python可以使用引號或者雙引號來定義字串,如下:
一般來說,字串的值本身包含單引號的情況下,我們一般使用雙引號來定義字串;同理,如果字串的值本身包含雙引號的情況下,我們可以使用單引號來定義字串,如下:
當然,python也可以使用轉譯字元來進行轉譯,轉譯字元是\。
\`:單引號
\n:換行
\a:響鈴
\b:退格,將當前位置移動到前一列
\f:換頁,將當前位置移動到下頁開頭
\r:回車,將當前位置移動到本行開頭
\t:水平製表,跳到下一個TAB位置
\v:垂直製表
\\:代表一個反斜槓字元'\'
在程式語言中,使用\定義轉譯字元,在URL中,使用%定義轉譯字元。
對於前面的例子,還可以用轉譯字元來表示:
大家透過前面的介紹,知道python遇到\時,會認為是一個轉移符,但是如下,可能改變我們的初衷:
上面的是因為python對\n進行了轉移,為了修正這個問題,我們可以在字串前面加一個r,表示使用原始字串,或者用\\進行轉移:
或者:
在python中,還可以使用三引號來定義字串,如下:
python字串還有一個容易忽略的特性,即兩個相連的字串會自動組成一個新字串:
1.2、字串是不可變的有序集合
python語言的字串有兩大特點:
1)字串是不可變的,不能直接對字串進行修改(python工程師應該謹記這個特性)
2)字串是字元的有序集合
python字串每次操作都會產生一個新的字串,新的字串會佔用一塊獨立的記憶體。因此,操作字串時需要避免產生太多的中間結果。
列舉元組裡面東西,應該用字串的join方法,如下:
Python字串可以透過下標和切片進行訪問。
a)下標操作每次只能訪問一個元素;
b)切片操作每次可以訪問一個範圍,可以指定切片操作的起點,終點和步長,也可以省略。
例子:
另外,下標和切片,可以應用於任何有序的集合,包括字串,元組,列表。
上面我們用如下方式進行了逆轉字串,但是這種可讀性不好:
In [52]: s[::-1] #這是切片,起點是開頭,結尾是末尾,步長是-1
Out[52]: 'dlrow,olleH'
逆轉字串不如使用reversed函式清晰,這種可讀性更好,如下:
2、字串函式
2.1 通用操作
相同的方式應用於列表中:
在Python語言的設計哲學中,字串、列表和元組具有一些共性,即他們都是元素的有序集合,python語言將對共性的操作提煉成了通用操作。因此,下標訪問、序列切片操作、求長度和判斷元素是否存在於集合中都是透過更加通用的函式和表示式提供支援。
2.2 與大小寫相關的方法
以下是幾個函式是與字元大小寫相關的字串處理函式:
1)upper:將字串轉換為大寫;
2)lower:將字串轉換為小寫;
3)isupper:判斷字串是否都為大寫;
4)islower:判斷字串是否都為小寫;
5)swapcase:將字串中的大寫轉換為小寫,小寫轉換為大寫;
6)capitalize:將首字元轉換為大寫;
7)istitle:判斷字串是不是一個標題。
例子:
[root@localhost ~]# python test3.py
Please input yes or no:"yes"
continue do something
3、判斷類方法
1)isupper:判斷字串是否都為大寫;
2)islower:判斷字串是否都為小寫;
3)isalpha:如果字串只包含字母,並且非空,則返回True,否則False;
4)isalnum:如果字串值包含字母和數字,並且非空,則返回True,否則False;
5)isspace:如果字串值包含空格、製表符、換行符,並且非空,則返回True,否則False;
6)isdecimal:如果字串只包含數字字元,並且非空,則返回True,否則False。
例子:
u"Python 3.6".isdecimal()
u/U:表示unicode字串
不是僅僅是針對中文, 可以針對任何的字串,代表是對字串進行unicode編碼。
一般英文字元在使用各種編碼下, 基本都可以正常解析, 所以一般不帶u;但是中文, 必須表明所需編碼, 否則一旦編碼轉換就會出現亂碼。
建議所有編碼方式採用utf8
4、字串方法startswith和endswith
startswith和endswith也是兩個判斷函式,用來判斷方法的引數是否為字串的字首和字尾。
下面我們看個使用的例子:
假設當前目錄下存在文字檔案、python檔案和圖片檔案,如下:
[root@localhost ~]# ls
a.txt b.txt c.txt d.txt e.py f.py g.py h.jpg
現在我們想找出所有文字檔案或者Python檔案,在python中使用內建的字串方法非常方法:
在我們的實際工作中,更多的時候可能需要字首匹配:
利用python檢視檔案大小:
5、查詢類函式
下面幾個函式都是用來查詢子串出現在字串中的位置,他們之間的區別就是查詢的方向不同,或者是處理異常情況的方式不同:
1)find:查詢子串出現在字串中的位置,如果查詢失敗,返回-1;
2)index:與find函式類似,如果查詢失敗,丟擲ValueError異常;
3)rfind:與find函式類似,區別在於rfind是從後向前找;
4)findex:與index類似,區別在於rindex是從後向橋找。
例子:
注意上面的 a = 'Return the lowest index in S where substring sub is found'裡面,有兩個in,第一個出現在下標18的位置,第二個出現在19的位置,在不指定範圍的情況下,查詢的是第一個in。
注意:find函式最容易用錯的地方在於使用find函式判斷一個子串是否出現在字串中。
判斷一個字串是否是另外一個字串的子串,正確的做法是使用In或者not in,如下:
6、字串操作方法
前面說過,python的字串是不可變的,無法修改。如果要修改原來的字串,可以對字串執行修改操作,將修改後的字串再賦值回原來的變數。
6.1 join函式
字串的join函式用以連線字串列表,組成一個新的、更大的字串。
另外,print函式本身就可以透過sep引數指定分割符進行拼接,不需要join函式,如下:
注:筆者發現只有python3的print才有sep功能。
6.2 split函式
split函式與join函式的作用正好相反,split將一個字串拆分成字串列表,如下:
6.3 strip函式
strip:對字串兩邊進行裁剪;
lstrip:對字串左邊進行裁剪;
rstrip:對字串右邊進行裁剪。
使用場景:strip函式使用最多的場景是去除字串兩邊的空白字元,如下:
當然,也可以給strip函式傳遞引數,引數中的所有字元都可以被裁剪,傳遞給strip函式的引數是需要裁剪的字符集合,因為是集合,所以字串的順序並不重要,重複字串也沒有任何效果,如下:
6.4、relapace函式
作用:將字串的子串替換成另外一個新的子串:
7、使用Python分析apache的訪問日誌
需求1:透過apache訪問日誌,統計PV和UV(pv是訪問的訪問請求數,uv是網站獨立訪客數)。
accesslog日誌如下:
注意:access.log最後一行不能是空行,否則列表會報錯,說下標超出範圍。
解釋:我們將解析出來的ip新增到一個列表中,那麼列表的長度就是網站的訪問數PV。當我們求UV時,只需要對剛才的列表進行去重,然後統計去重以後的元素個數,就得到UV。對於這個需求,在Python中可以透過將列表儲存到一個集合中實現,因為集合天生就具有去重的功能。
小知識,set建立集合
需求2:透過apache訪問日誌找到網站中最熱的資源(Counter)。
這個資訊對工程師來說非常有用,工程師知道哪些資源是比較熱的資源後,可以對這些資源的訪問進行額外的的最佳化,比如快取、反向代理、CDN等技術手段。
Python中可以使用collections.Counter儲存資源的熱度。
Counter是dict的子類,使用方式和字典類似,如下:
Counter是python2.7及以上版本才有的功能,這點要注意。
上面可以看到,Counter是使用一個字典儲存了資源的熱度,字典的鍵是資源的名稱,字典的值是訪問的次數。
下面的程式碼使用Counter統計網站中最熱4項資源:
cat d:\\temp\\accesslog.txt
下面是python程式碼:
cat test.py
>>>python test.py
Popular resources :[('/index.php', 4), ('/a.php', 1)]
需求3:統計網站的出錯比例
思路:如果HTTP CODE為2xx或3xx,則視為訪問正確;如果HTTP CODE為4xx或者5xx,則視為訪問出錯。
出錯比例=出錯的請求數/總請求數
方法:
python程式碼:
小知識: python字典的items方法作用:是可以將字典中的所有項,以列表方式返回。如果對字典項的概念不理解,可以檢視Python對映型別字典基礎知識一文。因為字典是無序的,所以用items方法返回字典的所有項,也是沒有順序的。 python字典的iteritems方法作用:與items方法相比作用大致相同,只是它的返回值不是列表,而是一個迭代器。 呼叫格式 字典items()與iteritems()都是函式,呼叫標準格式和其它函式格式是一樣的:變數.方法() 操作方法 字典items()操作方法: >>> x = {'title':'python web site','url':''} >>> x.items() [('url', ''), ('title', 'python web site')] 從結果中可以看到,items()方法是將字典中的每個項分別做為元組,新增到一個列表中,形成了一個新的列表容器。如果有需要也可以將返回的結果賦值給新變數,這個新的變數就會是一個列表資料型別。 >>> a=x.items() >>> a [('url', ''), ('title', 'python web site')] >>> type(a) <type 'list'> dict iteritems()操作方法: >>> f = x.iteritems() >>> f <dictionary-itemiterator object at 0xb74d5e3c> >>> type(f) <type 'dictionary-itemiterator'> #字典項的迭代器 >>> list(f) [('url', ''), ('title', 'python web site')] 字典.iteritems()方法在需要迭代結果的時候使用最適合,而且它的工作效率非常的高。 |
8、字串格式化
在python中,存在兩種格式化字串的方法,即%表示式和format函式。
雖然%表示式目前還被廣泛使用,但是format函式才是字串格式的為了,因此本節只介紹format函式。
最簡單的format函式使用應該是透過引數的位置訪問引數。如下所示,透過{}來表示一個佔位符,python會自動將format函式的引數依次傳遞給{}佔位符:
在引數較少的情況下,透過佔位符或下標的形式訪問format函式的引數並沒什麼問題,如果引數較多就不太適合了,這個時候可以使用解釋下更強的關鍵字引數形式,如下:
format函式也可以直接訪問物件的屬性,如下所示:
說明:namedtuple是繼承自tuple的子類。namedtuple建立一個和tuple類似的物件,而且物件擁有可訪問的屬性。
tuple是元組的意思。
下面的例子是對format函式的精度、符號、寬度、對齊方式、字元填充、逗號分隔等格式進行測試:
9、正規表示式
內建的字串處理函式能解決很多的字元處理問題,但是也是有一些比較複雜的情況,內建字串無法處理,或者沒法優雅的處理,這時用更具表達能力的正規表示式就好辦了。如下的一個字串,現在需要同時用":"和“.”進行split,這對於python的內建字串函式來說,就比較棘手了。但此時如果用正規表示式,就能輕鬆解決:
9.1正規表示式語法
1)要匹配給定文字中的所用單詞,可以使用下面的正規表示式:
?[a-zA-Z]+
?用於匹配單詞前後可能出現的空格,[a-zA-Z]+程式碼一個或多個英文字母。
2)要匹配一個ip,可以使用下面的正規表示式:
[0-9](1,3)\.[0-9](1,3)\.[0-9](1,3)\.[0-9](1,3)
表 1. 正規表示式基本語法
正規表示式的基本語法 | ||
正規表示式 | 描述 | 示例 |
^ | 行起始標記 | ^imp匹配以imp起始的行 |
$ | 行尾標記 | import$匹配以import結尾的行 |
, | 匹配任意一個字元 | 它只能匹配單個字元,但是可以匹配任意字元,如linu.可以匹配linux與linus |
[] | 匹配包含在[字元]之間的任意字元 | coo[lk]能夠匹配cook或者cool |
[^] | 匹配包含在[字元]之外的任意字元 | 9[^01]可以匹配92,93,但是不匹配91或90 |
[-] | 匹配[]中指定範圍內的任意一個字元 | [1-5]匹配1~5的任意一個數字,[a-z]匹配任意一個小寫字母 |
? | 匹配之前項的一次或0次 | hel?o匹配hello或helo,但不能匹配helllo |
+ | 匹配之前項的1次或多次 | hel+匹配hel和hell,但是不能匹配he |
* | 匹配之前項的0次或多次 | hel*匹配he,hel,hell |
{n} | 匹配之前項的n次 | [0-9]{3}匹配任意一個三位數 |
{n,} | 之前的項至少要匹配n次 | [0-9]{3,}匹配任意一個三位數或更多的數字 |
{n,m} | 指定之前的項所必須匹配的最小次數和最大次數 | [0-9]{2,5}匹配從兩位數到五位數之間的任意一個數字 |
特殊表示式序列 | 意義 |
---|---|
\A | 只在字串開頭進行匹配。 |
\b | 匹配位於開頭或者結尾的空字串 |
\B | 匹配不位於開頭或者結尾的空字串 |
\d | 匹配任意十進位制數,相當於 [0-9] |
\D | 匹配任意非數字字元,相當於 [^0-9] |
\s | 匹配任意空白字元,相當於 [ \t\n\r\f\v] |
\S | 匹配任意非空白字元,相當於 [^ \t\n\r\f\v] |
\w | 匹配任意數字和字母,相當於 [a-zA-Z0-9_] |
\W | 匹配任意非數字和字母的字元,相當於 [^a-zA-Z0-9_] |
\Z | 只在字串結尾進行匹配 |
9.2 利用re庫處理正規表示式
python中,標準庫的re模組用來處理正規表示式,它能夠順利處理unicode和普通字串,這個模組包含了與正規表示式相關的函式、標誌和一個異常。
最常用的是re模組下的findall函式,用來輸出所有符合模式匹配的子串,如下:
在python中,有兩種使用正規表示式的方式:
第一種就是直接使用re模組中的函式,正如前面例子演示的那樣;
第二種是建立一個特定模式編譯的正規表示式物件,然後使用這個物件的方法。
編譯的正規表示式:它是一個簡單的物件,透過傳遞模式給re.compile函式建立。
編譯和非編譯正規表示式,在效能方面是有差異的;如果需要處理的資料量比較大,編譯以後的正規表示式處理效率會更好。
編譯的正規表示式使用方法如下:
在python中,根據個人喜好選擇使用哪種正規表示式的方法,大部分情況下都不會有什麼問題。但是如果需要處理的資料量比較大,則使用編譯的正規表示式處理效能會更高。例如,我們使用Linux下的seq命令產生1000萬個整數儲存到檔案中,該資料檔案大約76M。接下來,對檔案的每一行應用模式[0-9]+,並使用linux下的time工具統計程式執行的時間。
非編譯的正規表示式版本原始碼如下:
編譯的正則表示版本原始碼如下:
可以看到:非編譯版本的python程式碼花費了16s,編譯版本程式碼花費了7s。
9.3 常用的re方法
9.3.1 匹配類函式
re模組中的findall函式。
re模組中的match函式類似於字串中的startswith函式,只是match應用在正規表示式中更強大,更具有表現力。match函式用以匹配字串的開始部分,如果匹配成功,
則返回一個SRE_Match型別的物件,如果匹配失敗,則返回一個None。因此,對於普通的字首匹配,它的用法和startswith一模一樣。例如我們要判斷data字串是否以What和not what開頭:
雖然簡單使用時match函式和startswith函式類似,但是對於複雜情況時,match函式能夠輕易解決,startswith則無能無力。例如我們需要判斷一個文字字元是否以一個數字開頭。由於我們不知道是哪個數字,只知道要求是數字,因此無法使用startswith函式,這個時候,可以使用re模組的match函式輕鬆解決,如下:
match函式匹配成功時返回SRE_Match型別的物件,也可以透過該物件獲取匹配的字串:
re模組中的search函式模式匹配成功時,也會返回一個SRE_Match物件。search函式與match函式用法幾乎一模一樣,區別在於search函式在字串的任意位置進行匹配,match函式僅在字串的開始部分進行匹配。他們的共同點是,如果匹配成功,返回SRE_Match物件,如果匹配失敗,返回一個None。
前面說過,search僅僅在查詢第一次匹配,也就是說,一個字串中包含了多個模式的匹配,也只返回第一個匹配的結果。如果我們要返回所有的結果應該怎麼做呢?返回所有結果的最簡單放放風就是用findall函式,除此之外,也可以使用finditer函式。
finditer返回一個迭代器,遍歷迭代器可以得到一個SRE_Match物件,如下:
9.3.2 修改類函式
re模組的sub函式類似於字串的replace函式,只是sub函式支援使用正規表示式。所以,re模組中的sub函式使用場景更加廣泛。
如下面的正規表示式,可以同時匹配2.7.13和3.6.0,並將它們都替換為x.x.x,如下:
利用sub函式將下面的日期進行格式化:
re模組的split函式與python字串的split函式功能一樣,都是將一個字串拆分成子串的列表,區別在於re模組的split函式能夠使用正規表示式。例如下面這段包含冒號、逗號、單引號和若干空格的文字,我們希望拆分出每一個單詞。面對這個需求python內建的split函式無法進行處理,因此我們可以直接使用re模組的split函式,re模組的split函式可以指定多個分隔符,如下:
說明:\s也是正規表示式,表示匹配任意空白。
9.3.3 大小寫不敏感
我們在字串查詢或替換的時候?忽略字元的大小寫,如下:
9.3.4非貪婪匹配
貪婪匹配:總是匹配最長的那個字串,預設使用貪婪匹配;
非貪婪匹配:匹配到那個最小的字串。
例子:
在下面的這個例子中,我麼你要匹配以Beautiful開頭並且以點號結尾的字串。顯然,存在兩個符合條件的匹配。預設情況下使用貪婪匹配,如果要使用非貪婪匹配,只需要在匹配的字串上加一個?,如下:
9.3.4 案例:獲取HTML頁面中的所有超連結
在這個例子中,我們使用開源的requests庫獲取Hack News的內容,然後使用正規表示式解析出所有的http或者https連結。
由於requests是一個開源專案,而不是標準庫,所有,使用之前需要安裝:
10 字符集編碼
把unicode字元表示為二進位制的方法有很多種,最常見的編碼方式是UTF-8,但是讀者需要注意的是,unicode是編寫形式,utf-8是儲存形式。UTF-8是使用最廣泛的編碼,但僅僅是unicode的一種儲存形式。使用python處理unicde時,如想把unicode字元轉換成二進位制資料,可以使用encode(編碼)方法;若想把二進位制資料轉換成unicode字元,可以使用decode(解碼)方法。此外,也可以使用pyhon2中的codecs模組和python3中的open函式來指定編碼型別。
在python 3中,字串預設為Unicode,但如果是在python 2中需要使用unicode,則必須在字串前面顯示的加上一個"u"字首,如下所示:
在python 2中,也可以使用預設的unicode字串,只需要執行下面的匯入即可:
python的字串具有encode編碼和decode解碼方法,下面是一個在python 2中的例子:
如果我們想把中文寫入檔案裡面,如果不保證字符集一致會報錯,如下:
上面報錯的原因是:
因為我們定義了一個unicode字串'u陳志新'。隨後,歐美想把這個字串儲存到文字檔案中,由於我們沒有指定文字檔案的編碼,所以預設是ASCII編碼,顯然unicode表示的漢子是無法使用ASCII編碼進行儲存的。所以python丟擲了UnicodeEncodeError異常。
解決辦法,手動編碼的方式解決,這是因為一個ASCII文字本身也是一個UTF-8文字。
小知識:unicode是表現形式,utf8是儲存形式。
如果需要寫入的字串比較多,而每次都需要進行編碼,程式將會變得非常低效,在python2中可以使用codecs模組,在python3內建的open函式已經支援編碼格式。指定編碼格式後,當我們寫入時會自動將unicode轉換為特定的編碼,讀取檔案時,會以特定的UTF進行解碼:
在python2中,使用codecs模組進行編碼(寫入檔案)和解碼(讀取檔案):
在python3中,內建的open函式可以指定字符集編碼:
在python程式設計中,應該把編碼和解碼操作放在程式的最外圍處理,程式的核心部分都使用unicode,為了在程式核心部分使用unicode,可以在程式碼中使用下面的輔助函式,函式能接受str或者unicode型別並且返回需要的字串型別:
python 2的字符集處理輔助函式:
python 3的字符集處理輔助函式:
11、jinja2模板
系統管理員和開發工程師應該經常使用模板來管理配置檔案。
渲染:可以使用模板將業務邏輯與頁面邏輯分隔開來。模板包含的是一個響應文字的檔案,其中包含用佔位符變數表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實的值替換變數,再返回最終得到的相應字串,這一過程稱為渲染。
一句話,渲染就是用真實的值替換變數。
python的標準庫自帶了一個簡單的模板,下面的例子就是。不過,Python自帶的模板功能非常有限,例如無法在模板中使用控制語句和表示式,不支援繼承和重用等操作,這對於web開發來說遠遠不夠,所以才出現了第三方的模板系統,最知名的就是jinja2和Mako。
11.1 jinja2模板語法入門
jinja2是Flask的一個依賴,如果已經安裝了Flask,jinja2也會隨之安裝。當然也可以單獨安裝jinja2:
[root@localhost ~]# pip install jinja2
[root@localhost ~]# python -c "import jinja2"
11.2 語法塊
在Jinja2中,存在三種語法:
a)控制結構{%%}
b)變數取值{}
c)註釋{##}
下面是一個使用jinja控制結構和註釋的一個例子:
{#note:disable temoate because we no longer use this
{% for user in users %}
....
{%endfor%}
#}
11.3 變數
jinja2模板中使用{{}}語法表示一個變數。jinja2識別所有的python資料型別,甚至是一個複雜的型別,如列表,字典和物件等,如下:
{{ mydict['key'] }}
{{ mylist[3] }}
{{ mylist[myintvar] }}
{{ myobj.somemethod{} }}
11.4 jinja2中的過濾器
過濾器可以理解為是jinja2裡面的內建函式和字串處理函式。
jinja2的常用過濾器 | |
過濾器名 | 說明 |
safc | 渲染時不轉譯 |
capitalize | 把值的首字母轉換成大寫,其他字母轉換成小寫 |
lower | 把值轉換為小寫形式 |
upper | 把值轉換為大寫形式 |
title | 把值中的每個單詞首字母轉換成大寫 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的html標籤都刪掉 |
join | 拼接多個值為字串 |
replace | 替換字串的值 |
round | 預設對數字進行四捨五入,也可以用引數進行控制 |
int | 把值轉換為整型 |
完整的過濾器列表可參見:
在Jinja2中,變數可以透過過濾器進行修改,過濾器和變數之間用管道 | 進行分割。多個過濾器可以鏈式呼叫,前一個過濾器的輸出會做為後一個過濾器的輸入,如下:
{{ "Hello World" | replace("Hello","Goodbye") }}
-->Goodbye World
{{ "Hello World" | replace("Hello","Goodbye") |upper }}
-->GOODYE WORLD
{{ 42.55 | round }}
---> 43.0
{{ 42.55 | round | int }}
---> 43
11.5 jinja2的控制結構
jinja2中的if語句類似於python中的if語句,但是,需要使用endif語句做為條件判斷的結束。我們可以使用if語句判斷一個變數是否定義,是否為空,是否為真值。與python中的if語句一樣,頁可以使用elif和else構建分支,如下:
{% if kenny.sick %}
kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!
{% else %}
Kenny looks ok
{% endif %}
11.6 jinja2的for迴圈
jinja2中的for語句可以迭代pytho的資料型別,包括列表、元組和字典。在jinja2中不存在while迴圈,這也符合了jinja2的“僅提供控制結構,不允許在模板中編寫太多的業務邏輯,避免工程師亂用的行為”的設計原則。
在jinja2中迭代列表:
在jinja2中也可以遍歷字典:
除了基本的for迴圈使用外,jinja2還提供了一些特殊的變數,我們不用定義就可以直接使用這些變數,如下:
變數 | 描述 |
loop.index | 當前迴圈迭代的次數,從1開始 |
loop.index0 | 當前迴圈迭代的次數,從0開始 |
loop.revindex | 到迴圈結束的次數,從1開始 |
loop.revindex0 | 到迴圈結束的次數,從0開始 |
loop.first | 如果是第一次迭代,為True,否則為False |
loop.last | 如果是最後一次迭代,為True,否則為False |
loop.length | 序列中的專案數 |
loop.cycle | 在一串序列間取值的輔助函式 |
需求:
假設你有一個儲存了聯絡人資訊的自動,字典的key是聯絡人的名字,字典的value是聯絡人的電話。你現在想把聯絡人的資訊以表格的形式顯示在HTML頁面上。此時除了姓名和電話外,你希望表格的第一列是序號,這個需要在python的程式碼中是這樣實現的:
jinja2為了防止工程師儘可能在模板中少寫python程式碼處理業務邏輯,僅在模板處理顯示工作問題,提供了一些特殊變數。對於上面的例子,在jinja2中正確的做法如下:
11.7 jinja2的宏
宏類似於程式語言宏的函式,它用於將行為抽象成可重複的程式碼塊,與函式一樣,宏分為定義和呼叫。
宏的定義的例子:
透過上面的例子可以看到,使用macro關鍵字定義一個宏,input是宏的名稱。它有三個引數,分別是name,type和value,其中type和value蠶食有預設值。可以看到宏的定義和python中的函式定義非常相似。此外,他與jinja2宏的for迴圈和if語句一樣,不需要使用複合語句的冒號,使用endmacro結束宏的定義。
宏的呼叫的例子:
11.8 jinja2的繼承和Super函式
如果只是用jinja2進行配置檔案的管理,將基本用不到jinja2的繼承功能。如果是使用Jinja2進行web開發,那麼,繼承將是jinja2最吸引人的功能。
jinja2中最強大的部分就是模板的繼承。模板繼承允許你構建一個包含站點共同元素的基本模板“骨架”,並定義子模板可以覆蓋的塊。
假設我們有一個名為base.html的HTML文件,裡面內容如下:
在base.html中,我們使用{% block name %}的方式定義了三個塊,這些塊可以在子模板中進行替換或呼叫。
下面是一個名為index,html的HTML文件,文件的內容如下:
在上面的Index.html中,我們使用{% extends "base.html" %}繼承base.html,繼承以後,base.html中的所有內容都會在index.html中展現。在Index.html中,我們重新定義了title和content這連個塊的內容。
Super是繼承的意思。
11.9 jinja2的其他運算
jinja2中可以定義變數,為了對變數進行操作,jinja2提供了算數操作、比較操作和邏輯操作。使用jinja2模板時,應該儘可能在python程式碼中進行邏輯處理,在jinja2中僅處理顯示問題。因此,一般很少用到jinja2的變數和比那裡的運算操作。
部分jinja2的運算操作:
a)算術運算:+-* % * **
b)比較操作:== != > >= < <=
c) 邏輯操作:not and or
12 jinja2實戰
jinja2模組中有一個名為Environment的類,這個類的例項用於儲存配置和全域性物件,然後從檔案系統其他位置載入模板。
大多數應用都在初始化時建立一個Environment物件並用它載入模板。配置jinja2為應用載入文件的最簡單方式大概是這樣的:
上面的程式碼會建立一個Environment物件和一個包載入器,該載入器會在yourapplication這個python包的templates目錄下查詢模板。接下來,只需要以模板的名字做為引數呼叫Environment.get_template方法即可。該方法會返回一個模板,最後使用模板的render方法進行渲染,如下:
除了使用包載入器外,還可以使用檔案系統載入器。檔案系統載入器不需要模板位於一個python包下,可以直接訪問系統中的檔案。為了便於功能演示,我們將在接下來請的例子中使用下面的輔助函式:
備註:
tpl_path:模板路徑
**kwargs:需要渲染模板裡面的引數
小知識:
如果是函式定義中引數前的*表示的是將呼叫時的多個引數放入元組中,**則表示將呼叫函式時的關鍵字引數放入一個字典中
如定義以下函式
def func(*args):print(args)
當用func(1,2,3)呼叫函式時,引數args就是元組(1,2,3)
定義以下函式
def func(**args):print(args)
當用func(a=1,b=2)呼叫函式時,引數args將會是字典{'a':1,'b':2}
12.1 基本功能演示
下面來看一個模板渲染的例子,假設我們存在一個名為simple.html的文字檔案,它的內容如下:
在這個HTML模板中,我們使用for迴圈遍歷一個列表,列表中每一個項是一個字典,字典中包含了文字和連結,我們將使用字典中的資料渲染成HTML的超連結。此外,我們還會使用jinja2提供的過濾器trim刪掉titile裡面的空格。
小知識
a)、locals返回當前作用域 的所有區域性變數的變數名:變數值組成的字典。
例如:當前作用域有兩個區域性變數x=1,y='something'則locals()返回字典
{'x':1,'y':'something'}
b)、**locals()在format函式呼叫裡的意思是將locals()返回的字典解包傳遞給format函式。如果locals返回的如上面的例子裡說的 一樣的話,解包就是將{'x':1,'y':'something'}變成x=1,y='something'
執行上面程式碼,渲染模板的結果為:
12.2 繼承功能演示
為了演示繼承的功能,我們需要使用兩個html檔案,分別是base.html和index.html。
base.html內容如下:
index.html的內容如下:
我們使用下面的python程式碼渲染jinja2模板:
渲染後的結果為:
從這個例子可以看到:
1)、我們渲染的是index.html,並沒有直接渲染base.html,但是最後生成的模板中包含了完整的html框架,這也是繼承廣泛的使用場景;
2)、我們雖然在index.html中定義了title塊。但是,因為我們使用了{{super}}引用了base.html中的HEAD塊。因此,最後的渲染結果中包含了base.html中的head塊和index.html中的head塊。例如,最後渲染的結果中title標籤的內容是“index -My Webpage”,這個字串就來自index,html和base.html。
3)、我們在index.html中重新定義了content塊的內容,因此,最後生成的文件中在正確的位置顯示了content塊的內容。
12.3 案例:使用jinja2生成HTML表格和XML配置檔案
1、使用jinja2生成html表格
模板hzfc.html:
渲染模板的python程式碼:
執行結果:
2、使用jinja2生成xml配置檔案
應用場景:部署應用可以自動化,但是生成配置檔案就比較困難,這是因為配置檔案的取值是動態取值的,如果使用shell指令碼,只能透過sed進行動態的替換,shell指令碼處理這種情況比較複雜,而且容易出錯,可讀性差。對於這裡的需求,最好的方法是使用模板,透過模板渲染的方式,將底層的服務的Ip和埠號寫入一個配置檔案中,隨後用Python程式碼讀取配置檔案,渲染配置檔案生成新的配置檔案。
在本例中,有一個名為base.cfg的配置檔案,該檔案儲存了配置引數的取值:
此外,還有一個名為pass_service1_template.xml的配置模板,模板的內容如下:
在本例中,存在兩個上層服務,另外一個上層服務的配置模板名稱為pass_service2_template.xml,內容如下:
現在的需求是讀入配置檔案base.cfg,然後使用jinja2模板渲染技術,將兩個上層服務的配置模板pass_service1_template.xml和pass_service2_template.xml渲染成配置檔案。相關的python程式碼如下:
本文使用了一個小技巧,即透過給globals字典賦值的方式定義全域性變數,然後將所有的全域性變數傳遞給模板,模板渲染時只會使用到自己需要的變數,渲染完成後會在當前目錄下生成兩個配置檔案,分別是pass_server1.xml和pass_server2.xml。
pass_server1.xml的內容如下:
pass_server2.xml的內容如下:
小知識:
locals 是隻讀的,不可修改, 而globals可以修改,原因是:
locals()實際上沒有返回區域性名字空間,它返回的是一個複製。所以對它進行修改,修改的是複製,而對實際的區域性名字空間中的變數值並無影響。
globals()返回的是實際的全域性名字空間,而不是一個複製: 與 locals 的行為完全相反。
所以對 globals 所返回的 dictionary 的任何的改動都會直接影響到全域性變數的取值。
定義一個函式
結果:
{'x': 1, 'arg': 3}
x= 1
{'x': 1, 'arg': 3}
x= 1
{'foo': <function foo at 0x02A17CF0>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:\\workspace\\python day03\\main\\test.py', '__package__': None, '__name__': '__main__', 'z': 7, '__doc__': 'This is my first python program!'}
z= 7
{'foo': <function foo at 0x02A17CF0>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:\\workspace\\python day03\\main\\test.py', '__package__': None, '__name__': '__main__', 'z': 8, '__doc__': 'This is my first python program!'}
z= 8
(完)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28916011/viewspace-2150113/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python深度學習(處理文字資料)--學習筆記(十二)Python深度學習筆記
- CSS 小結筆記之文字溢位處理CSS筆記
- python 文字處理操作Python
- Python筆記(五)——檔案處理Python筆記
- 9,以正則表達處理文字(perl筆記)筆記
- 《Python資料處理》讀書筆記Python筆記
- Python檔案處理-專題筆記Python筆記
- Python自然語言處理 3 處理原始文字Python自然語言處理
- Python文字資料分析與處理Python
- Golang正則筆記 :使用正規表示式處理題庫文字Golang筆記
- 【筆記】基於Python的數字影象處理筆記Python
- 文字處理用c還是用pythonPython
- 【python技巧】文字處理-re庫字元匹配Python字元
- java異常處理筆記Java筆記
- Python自然語言處理學習筆記(57):小結Python自然語言處理筆記
- python-文字處理和正規表示式Python
- 機器學習筆記---資料預處理機器學習筆記
- OpenCV3影像處理筆記OpenCV筆記
- React學習筆記-事件處理React筆記事件
- python自然語言處理學習筆記(八)—— 句法分析Python自然語言處理筆記
- 《Python Cookbook 3rd》筆記(4.13):建立資料處理管道Python筆記
- Python自然語言處理學習筆記(66):7.7 小結Python自然語言處理筆記
- Python文字處理NLP:分詞與詞雲圖Python分詞
- 記個格式化時間處理筆記筆記
- JSP筆記-XML 資料處理JS筆記XML
- Go 的錯誤處理策略 筆記Go筆記
- Django 上下文處理器 筆記Django筆記
- 【影像處理筆記】小波變換筆記
- Vue學習筆記之事件處理Vue筆記事件
- 【筆記】jQuery原始碼(文件處理3)筆記jQuery原始碼
- oracle壞塊模擬處理(筆記)Oracle筆記
- 異常處理-PHP手冊筆記PHP筆記
- 10 文字分析處理命令
- Linux文字處理命令Linux
- 簡單的文字處理
- 文字處理的有關
- [python] LDA處理文件主題分佈程式碼入門筆記PythonLDA筆記
- Python編解碼問題與文字檔案處理Python