Python 18(2) ?miniweb項(xiàng)目

MiniWEB項(xiàng)目琅坡、模版悉患、使用正則進(jìn)行替換 {\%content\%} 為內(nèi)容、路由榆俺、裝飾器實(shí)現(xiàn)路由购撼、AOP面向切面編程、SEO搜索引擎優(yōu)化 實(shí)現(xiàn)偽靜態(tài)服務(wù)器

3.2 MiniWEB項(xiàng)目

學(xué)習(xí)目標(biāo)

? 1. 能夠說(shuō)出路由的概念

? 2. 能夠說(shuō)出什么是面向切片編程

? 3. 能夠說(shuō)出模板文件的使用

--------------------------------------------------------------------------------

3.2.1 實(shí)現(xiàn)框架

在這部分內(nèi)容中主要實(shí)現(xiàn)框架的搭建,利用模板來(lái)實(shí)現(xiàn)基本頁(yè)面的顯示(目前的數(shù)據(jù)還是靜態(tài)的)

這部分內(nèi)容中將不在顯示靜態(tài) API 頁(yè)面

新創(chuàng)建一個(gè)項(xiàng)目,將資源文件夾拷貝到項(xiàng)目的文件夾中去(拷貝方式見(jiàn)前一章節(jié)),文件夾中的內(nèi)容暫時(shí)不用考慮

資源文件夾介紹: dynamic 文件夾中用來(lái)存放處理動(dòng)態(tài)數(shù)據(jù)的文件,也就是我們的 WEBFrame 文件 static文件夾中有兩個(gè)文件夾,CSS和JS,CSS 文件夾存放對(duì)頁(yè)面樣式文件谴仙,JS 文件夾存放對(duì)頁(yè)面交互動(dòng)作的文件templates 文件夾中實(shí)現(xiàn)好了三個(gè)頁(yè)面的顯示模板,實(shí)現(xiàn)好了頁(yè)面的顯示基本框架,我們只需要利用框架,向框架里添加顯示數(shù)據(jù)即可

3.2.2 創(chuàng)建工程,導(dǎo)入資源模板文件

? 實(shí)現(xiàn)過(guò)程:

? 1. 打開(kāi)工程文件位置,將三個(gè)文件夾復(fù)制到工程文件夾中.將 WEBServer 和 WEBFrame 文件也復(fù)制進(jìn)去

? 2. 一般的情況下,會(huì)將數(shù)據(jù)處理的 WEBFrame 文件放到 dynamic 目錄下

? 實(shí)現(xiàn)代碼:

? ? ? 修改導(dǎo)入的相應(yīng)文件和調(diào)用 因?yàn)閿?shù)據(jù)文件被創(chuàng)建在 dynamic 這個(gè)文件夾下,所以在導(dǎo)入時(shí),需要form-import 方式導(dǎo)入模塊

? WebServer.py

from dynamic import WEBFrame

# 其它無(wú)修改

3.2.3 使用模板 Index 頁(yè)面實(shí)現(xiàn)首頁(yè)數(shù)據(jù)顯示

? 頁(yè)面在顯示時(shí),很多時(shí)候顯示框架都是一樣的,只是顯示的內(nèi)容不同

? ? ? 比如新聞頁(yè)面,都有標(biāo)題,時(shí)間,作者,內(nèi)容等等固定的顯示形式和位置

? 所以只需要將具體的新聞內(nèi)容加到寫(xiě)好的框架中顯示即可,這就是模板的作用

? 實(shí)現(xiàn)過(guò)程:

? 1. 服務(wù)文件到此基本上不會(huì)再做修改

? 2. 主要都是在數(shù)據(jù)處理文件上進(jìn)行處理

? 3. 因現(xiàn)目前的工程已經(jīng)不在訪問(wèn)API頁(yè)面,并且的所有的頁(yè)面布局文件都在static目錄下存放

? 4. 在數(shù)據(jù)處理文件中根據(jù)訪問(wèn)的路徑,拼接需要顯示的html模板文件,然后拼接文件地址 './templates/index.html'

? 5. 然后讀取文件中的內(nèi)容

? 6. 將文件中需要顯示內(nèi)容的地方,使用正則進(jìn)行替換 {\%content\%} 為內(nèi)容

? 7. 可以多加入一些數(shù)據(jù)

? 8. 準(zhǔn)備插入的數(shù)據(jù):

row_str = """

? ? ? ? <tr>

? ? ? ? ? ? <td>1</td>

? ? ? ? ? ? <td>000007</td>

? ? ? ? ? ? <td>全新好</td>

? ? ? ? ? ? <td>10.01%</td>

? ? ? ? ? ? <td>4.40%</td>

? ? ? ? ? ? <td>16.05</td>

? ? ? ? ? ? <td>14.60</td>

? ? ? ? ? ? <td>2017-07-18</td>

? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007">

? ? ? ? ? ? </td>

? ? ? ? </tr>? """

將數(shù)據(jù)顯示到頁(yè)面中

? 實(shí)現(xiàn)代碼:

WebServer.py

# ...

# 前面的代碼不需要修改

# ------------- 這里開(kāi)始修改代碼------------

? ? try:

? ? ? ? #拼接路徑,因現(xiàn)目前的工程已經(jīng)不在訪問(wèn)API頁(yè)面,并且的所有的 html 頁(yè)面模板布局文件都在 static 目錄下存放

? ? ? ? #為了能正確的讀取頁(yè)面布局文件,所以要將原來(lái) ./html 修改為./static,程序會(huì)到 static 目錄下找訪問(wèn)的路徑對(duì)應(yīng)的模板文件進(jìn)行讀取

? ? ? ? f = open("./static" + file_name, "rb")

? ? except:

# 后面的代碼不需要修改

# ...

WebFrame.py

# 因?yàn)橐褂谜齽t替換模板文件中的內(nèi)容碾盐,所以先導(dǎo)入模塊

import re

# 實(shí)現(xiàn) WSGI 協(xié)議中的 application 接口方法

def application(environ, start_response):

? ? # 從服務(wù)器傳過(guò)來(lái)的字典中將訪問(wèn)路徑取出來(lái)

? ? url_path = environ['PATH_INFO']

? ? # 準(zhǔn)備一個(gè)用來(lái)保存讀取模板文件內(nèi)容的變量

? ? if url_path == '/index.py':

? ? ? ? path = './templates/index.html'

? ? ? ? # 讀取模板文件中的內(nèi)容

? ? ? ? with open(path, 'r') as f:

? ? ? ? ? ? file_content = f.read()

? ? ? ? # 替換的假數(shù)據(jù)(后面需要從數(shù)據(jù)庫(kù)里讀然味濉)

? ? ? ? row_str = """

? ? ? ? ? ? ? ? ? ? <tr>

? ? ? ? ? ? ? ? ? ? ? ? <td>1</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>000007</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>全新好</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>10.01%</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>4.40%</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>16.05</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>14.60</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>2017-07-18</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? ? ? <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007">

? ? ? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? ? ? </tr>? """

? ? ? ? # 準(zhǔn)備多條數(shù)據(jù)

? ? ? ? all_data = ""

? ? ? ? for i in range(20):

? ? ? ? ? ? all_data += row_str

? ? ? ? # 將行數(shù)據(jù),利用正則,將數(shù)據(jù)替換到模板中{%content%} 為了避免打錯(cuò),建議復(fù)制

? ? ? ? # 第一個(gè)參數(shù)為正則,用來(lái)匹配模板中的內(nèi)容

? ? ? ? # 參數(shù)二為要替換上去的內(nèi)容

? ? ? ? # 參數(shù)三是要被替換的字符串

? ? ? ? # 替換后重新更新數(shù)據(jù)并返回

? ? ? ? # 正則表達(dá)式中,因?yàn)閧}本身在正則中有限定符的作用毫玖,但是這里要替換的字符串包括{}掀虎,所以在{}前加上\,表示匹配{}

? ? ? ? file_content = re.sub(r'\{%content%\}', all_data, file_content)

? ? elif url_path == '/center.py':

? ? ? ? file_content = 'Center Page ...'

? ? else:

? ? ? ? file_content = 'Other Page ...'

? ? # 回調(diào) start_response 函數(shù)付枫,將響應(yīng)狀態(tài)信息回傳給服務(wù)器

? ? start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

? ? # 返回響應(yīng)數(shù)據(jù)內(nèi)容

? ? return file_content

利用模板烹玉,將制做的假數(shù)據(jù)顯示到頁(yè)面成功。

3.2.4 使用模板 Center 頁(yè)面實(shí)現(xiàn)首頁(yè)數(shù)據(jù)顯示

實(shí)現(xiàn)過(guò)程:

? 1. 個(gè)人中心頁(yè)面顯示同理首頁(yè)

? 2. 在數(shù)據(jù)處理文件中根據(jù)訪問(wèn)的路徑,拼接需要顯示的html模板文件,然后拼接文件地址 './templates/center.html'

? 3. 然后讀取文件中的內(nèi)容

? 4. 將文件中需要顯示內(nèi)容的地方,使用正則進(jìn)行替換 {\%content\%} 為內(nèi)容

? 5. 可以多加入一些數(shù)據(jù)

? 6. 準(zhǔn)備顯示的數(shù)據(jù):

row_str = """

? ? <tr>

? ? ? ? <td>000426</td>

? ? ? ? <td>興業(yè)礦業(yè)</td>

? ? ? ? <td>0.41%</td>

? ? ? ? <td>2.17%</td>

? ? ? ? <td>9.71</td>

? ? ? ? <td>9.67</td>

? ? ? ? <td>今天的漲幅不錯(cuò),希望每天如此</td>

? ? ? ? <td>

? ? ? ? ? ? <a type="button" class="btn btn-default btn-xs" href="/update/000426.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>

? ? ? ? </td>

? ? ? ? <td>

? ? ? ? ? ? <input type="button" value="刪除" id="toDel" name="toDel" systemidvaule="000426">

? ? ? ? </td>

? ? </tr> """

將數(shù)據(jù)顯示到頁(yè)面中

? 實(shí)現(xiàn)代碼: WebFrame.py

? ? # ...

? ? # 前面的代碼不需要修改

? ? # ------------- 這里開(kāi)始修改代碼------------

? ? elif url_path == '/center.py':

? ? ? ? path = './templates/center.html'

? ? ? ? with open(path, 'r') as f:

? ? ? ? ? ? file_content = f.read()

? ? ? ? row_str = """

? ? ? ? ? ? ? ? <tr>

? ? ? ? ? ? ? ? ? ? <td>000426</td>

? ? ? ? ? ? ? ? ? ? <td>興業(yè)礦業(yè)</td>

? ? ? ? ? ? ? ? ? ? <td>0.41%</td>

? ? ? ? ? ? ? ? ? ? <td>2.17%</td>

? ? ? ? ? ? ? ? ? ? <td>9.71</td>

? ? ? ? ? ? ? ? ? ? <td>9.67</td>

? ? ? ? ? ? ? ? ? ? <td>今天的漲幅不錯(cuò),希望每天如此</td>

? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? <a type="button" class="btn btn-default btn-xs" href="/update/000426.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>

? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? <input type="button" value="刪除" id="toDel" name="toDel" systemidvaule="000426">

? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? </tr> """

? ? ? ? all_data = ''

? ? ? ? for i in range(5):

? ? ? ? ? ? all_data += row_str

? ? ? ? file_content = re.sub(r'\{%content%\}', all_data, file_content)

? ? ? ? # 后面的代碼不需要修改

? ? ? ? # ...

3.2.5 代碼優(yōu)化阐滩,抽取函數(shù)

通過(guò)上面的代碼可以看出二打,如果頁(yè)面很多的話,那么我們就要不斷的的將功能實(shí)現(xiàn)代碼寫(xiě)入到 if-else 中,那么這個(gè)一個(gè)函數(shù)中的代碼就會(huì)非常大,非常不符合代碼開(kāi)發(fā)的規(guī)范。

好不容易從服務(wù)器文件中分離出來(lái)的代碼掂榔,在這里還是一坨继效,顯然是不合適的。那么怎么將這部分代碼再優(yōu)化一下呢装获?

可以將每個(gè)頁(yè)面的功能抽取成單獨(dú)的函數(shù),然后只需要在if中調(diào)用訪問(wèn)路徑相應(yīng)的函數(shù)執(zhí)行瑞信。如果再加入新功能,只需要再加入新方法就可以了穴豫。代碼管理非常清晰凡简。

? 實(shí)現(xiàn)過(guò)程:

? 1. 抽取方法

? 2. 調(diào)用函數(shù)

? 實(shí)現(xiàn)代碼: WebFrame.py

# 因?yàn)橐褂谜齽t替換模板文件中的內(nèi)容,所以先導(dǎo)入模塊

import re

# 實(shí)現(xiàn) WSGI 協(xié)議中的 application 接口方法

def application(environ, start_response):

? ? # 從服務(wù)器傳過(guò)來(lái)的字典中將訪問(wèn)路徑取出來(lái)

? ? url_path = environ['PATH_INFO']

? ? # 根據(jù)訪問(wèn)的頁(yè)面來(lái)調(diào)用相應(yīng)的方法

? ? if url_path == '/index.py':

? ? ? ? file_content = index()

? ? elif url_path == '/center.py':

? ? ? ? file_content = center()

? ? else:

? ? ? ? file_content = other()

? ? # 回調(diào) start_response 函數(shù),將響應(yīng)狀態(tài)信息回傳給服務(wù)器

? ? start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

? ? # 返回響應(yīng)數(shù)據(jù)內(nèi)容

? ? return file_content

#首頁(yè)響應(yīng)的函數(shù)

def index():

? ? path = './templates/index.html'

? ? # 讀取模板文件中的內(nèi)容

? ? with open(path, 'r') as f:

? ? ? ? file_content = f.read()

? ? # 替換的假數(shù)據(jù)(后面需要從數(shù)據(jù)庫(kù)里讀瘸由)

? ? row_str = """

? ? ? ? ? ? ? ? ? ? <tr>

? ? ? ? ? ? ? ? ? ? ? ? <td>1</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>000007</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>全新好</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>10.01%</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>4.40%</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>16.05</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>14.60</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>2017-07-18</td>

? ? ? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? ? ? <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007">

? ? ? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? ? ? </tr>? """

? ? # 準(zhǔn)備多條數(shù)據(jù)

? ? all_data = ""

? ? for i in range(20):

? ? ? ? all_data += row_str

? ? # 將行數(shù)據(jù),利用正則,將數(shù)據(jù)替換到模板中{%content%} 為了避免打錯(cuò),建議復(fù)制

? ? # 第一個(gè)參數(shù)為正則,用來(lái)匹配模板中的內(nèi)容

? ? # 參數(shù)二為要替換上去的內(nèi)容

? ? # 參數(shù)三是要被替換的字符串

? ? # 替換后重新更新數(shù)據(jù)并返回

? ? file_content = re.sub(r'\{%content%\}', all_data, file_content)

? ? return file_content

# 個(gè)人中心頁(yè)面響應(yīng)的函數(shù)

def center():

? ? path = './templates/center.html'

? ? with open(path, 'r') as f:

? ? ? ? file_content = f.read()

? ? row_str = """

? ? ? ? ? ? ? ? <tr>

? ? ? ? ? ? ? ? ? ? <td>000426</td>

? ? ? ? ? ? ? ? ? ? <td>興業(yè)礦業(yè)</td>

? ? ? ? ? ? ? ? ? ? <td>0.41%</td>

? ? ? ? ? ? ? ? ? ? <td>2.17%</td>

? ? ? ? ? ? ? ? ? ? <td>9.71</td>

? ? ? ? ? ? ? ? ? ? <td>9.67</td>

? ? ? ? ? ? ? ? ? ? <td>今天的漲幅不錯(cuò),希望每天如此</td>

? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? <a type="button" class="btn btn-default btn-xs" href="/update/000426.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>

? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? ? ? <td>

? ? ? ? ? ? ? ? ? ? ? ? <input type="button" value="刪除" id="toDel" name="toDel" systemidvaule="000426">

? ? ? ? ? ? ? ? ? ? </td>

? ? ? ? ? ? ? ? </tr> """

? ? all_data = ''

? ? for i in range(5):

? ? ? ? all_data += row_str

? ? file_content = re.sub(r'\{%content%\}', all_data, file_content)

? ? return file_content

# 其它頁(yè)面響應(yīng)的函數(shù)

def other():

? ? return 'Other Page ...'

3.2.6 路由

? <1>什么是路由帜乞?

? ? ? 路由是指根據(jù)請(qǐng)求的地址,決定到目標(biāo)的路徑過(guò)程溉仑。這是一個(gè)計(jì)算機(jī)通用概念挖函,一般使用在網(wǎng)絡(luò)中。

? ? ? 在 Web框架中浊竟,路由是指客戶端把請(qǐng)求發(fā)送給 Web 服務(wù)器怨喘,Web 服務(wù)器再把請(qǐng)求發(fā)送給程序?qū)嵗3绦驅(qū)嵗枰缹?duì)每個(gè) URL 請(qǐng)求運(yùn)行哪些代碼振定,所以程序?qū)嵗4媪艘粋€(gè) URL 到 Python 函數(shù)的映射關(guān)系必怜。處理URL和函數(shù)之間關(guān)系的程序稱路由。

? 在上面的代碼中后频,if 函數(shù)就實(shí)現(xiàn)了簡(jiǎn)單的路由功能梳庆,if 函數(shù)通過(guò)訪問(wèn)路徑來(lái)決定調(diào)用哪個(gè)函數(shù)來(lái)執(zhí)行返回。上面的代碼雖然抽取了方法,實(shí)現(xiàn)了簡(jiǎn)單的路由功能卑惜,但是調(diào)用起來(lái)依然很繁瑣膏执,我們還是要在程序入加入很多的if-else,來(lái)實(shí)現(xiàn)函數(shù)的調(diào)用。那么有沒(méi)有辦法更簡(jiǎn)單的實(shí)現(xiàn)路由功能呢露久?

? 為了解決這個(gè)問(wèn)題,我們?cè)诖嘶A(chǔ)上,利用字典的鍵值對(duì)實(shí)現(xiàn)路由來(lái)調(diào)用函數(shù)

? 創(chuàng)建一個(gè)字典更米,使用字典保存 訪問(wèn)路徑 和 對(duì)應(yīng)方法 的鍵值對(duì)

? 通過(guò)在字典中查找訪問(wèn)的路徑來(lái)找到對(duì)應(yīng)的函數(shù)進(jìn)行調(diào)用實(shí)現(xiàn)路由。

? 實(shí)現(xiàn)過(guò)程:

? 1. 創(chuàng)建一個(gè)用來(lái)保存訪問(wèn)路徑和對(duì)應(yīng)函數(shù)的字典,并將鍵值對(duì)關(guān)系存入字典中

? 2. 當(dāng)訪問(wèn)頁(yè)面時(shí),通過(guò)訪問(wèn)路徑得到對(duì)應(yīng)的函數(shù),然后執(zhí)行

? 3. 如果以后有新的頁(yè)面添加,那么就向字典中加入新的鍵值對(duì)即可

? 實(shí)現(xiàn)代碼: WebFrame.py

def application(environ, start_response):

? ? # 從服務(wù)器傳過(guò)來(lái)的字典中將訪問(wèn)路徑取出來(lái)

? ? url_path = environ['PATH_INFO']

? ? # ------------- 這里開(kāi)始修改代碼------------

? ? # 創(chuàng)建一個(gè)路由字典毫痕,將訪問(wèn)路徑和響應(yīng)函數(shù)的鍵值對(duì)加入到字典中

? ? router_dict = {'/index.py': index, '/center.py': center}

? ? # 判斷訪問(wèn)的路徑在不在字典的key中

? ? if url_path in router_dict:

? ? ? ? # 如果在征峦,在字典中查找傳入的訪問(wèn)路徑,找到對(duì)應(yīng)的函數(shù)

? ? ? ? function = router_dict[url_path]

? ? else:

? ? ? ? # 如果不在消请,那么設(shè)置一個(gè)默認(rèn)函數(shù)栏笆,不然頁(yè)面無(wú)法顯示,不友好

? ? ? ? function = other

? ? # 執(zhí)行函數(shù)得到數(shù)據(jù)

? ? file_content = function()

? ? # ------------- 這里結(jié)束修改代碼------------

? ? # 回調(diào) start_response 函數(shù)臊泰,將響應(yīng)狀態(tài)信息回傳給服務(wù)器

? ? start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

? ? # 返回響應(yīng)數(shù)據(jù)內(nèi)容

? ? return file_content

通過(guò)字典來(lái)實(shí)現(xiàn)路由蛉加,使代碼更加簡(jiǎn)單。

3.2.7 擴(kuò)展裝飾器傳參

知識(shí)點(diǎn)擴(kuò)展:

裝飾器也可以傳參

# 定義帶參數(shù)的裝飾器

def set_args(args):

? ? print(args)

? ? def set_fun(func):

? ? ? ? print('set_func')

? ? ? ? def wrapper(*args,**kwargs):

? ? ? ? ? ? print('wrapper')

? ? ? ? ? ? return func(*args,**kwargs)

? ? ? ? return wrapper

? ? return set_fun

# 利用裝飾器來(lái)裝飾函數(shù)

@set_args('args-string')

def show():

? ? print('show')

# 調(diào)用函數(shù)

show()

程序執(zhí)行結(jié)果:

args-string

set_func

wrapper

show

裝飾器本來(lái)就是使用閉包來(lái)實(shí)現(xiàn)的缸逃,而閉包就是一種函數(shù)嵌套實(shí)現(xiàn)的形式七婴。

帶參的裝飾器就是在原有裝飾閉包函數(shù)外又套了一層函數(shù)

裝飾器在執(zhí)行裝飾過(guò)程中,先將裝飾器當(dāng)成一個(gè)函數(shù)來(lái)調(diào)用察滑,得到內(nèi)部函數(shù)的引用打厘,然后再將這個(gè)內(nèi)部函數(shù)做為真正的裝飾器來(lái)裝飾實(shí)際函數(shù)。

帶參裝飾器執(zhí)行過(guò)程:

? 1. 先執(zhí)行set_args('參數(shù)') 得到 set_args函數(shù)中的返回值,也就是set_fun函數(shù)的引用

? 2. 然后返回的引用和@進(jìn)行組合,變成裝飾器形式 @set_fun , 但是這時(shí)set_fun 函數(shù)因?yàn)槭欠祷氐拈]包引用,所以保留了args的參數(shù)值

? 3. 再調(diào)用 show 的時(shí)候,show 還是指向的 wrapper 函數(shù)贺辰,但是在這個(gè)函數(shù)中户盯,可以使用外面兩層函數(shù)的變量或參數(shù)

? 4. 無(wú)論在何時(shí)嵌施,閉包有幾層,最終被裝飾的函數(shù)永遠(yuǎn)指向 wrapper 函數(shù)

裝飾器有了傳參莽鸭,那么能不能利用這個(gè)特性吗伤,來(lái)改進(jìn)一下我們的代碼呢?

3.2.8 裝飾器實(shí)現(xiàn)路由

前面版本的代碼在實(shí)現(xiàn)函數(shù)的調(diào)用時(shí)硫眨,還是需要做大量的鍵值對(duì)添加工作

那么我們是不是可以利用裝飾器傳參來(lái)自動(dòng)進(jìn)行向字典中添加訪問(wèn)路徑和函數(shù)之間的關(guān)系呢?

如果可以,那么以后,我們只需要完成訪問(wèn)頁(yè)面的響應(yīng)函數(shù)就可以了足淆,這個(gè)也是必須要寫(xiě)的

然后在響應(yīng)函數(shù)前面加上裝飾器,讓裝飾器自動(dòng)將鍵值對(duì)關(guān)系添加到字典中礁阁。這樣的話就不需要再手動(dòng)添加鍵值對(duì)關(guān)系了巧号。

實(shí)現(xiàn)過(guò)程:

? 1. 創(chuàng)建一個(gè)用來(lái)保存鍵值對(duì)關(guān)系的空字典

? 2. 創(chuàng)建一個(gè)帶參的閉包裝飾器

? 3. 在閉包裝飾器中傳入訪問(wèn)的頁(yè)面路徑,然后利用路徑,將函數(shù)本身加入到字典中

? 4. 為每個(gè)實(shí)現(xiàn)的函數(shù)都加上這個(gè)裝飾器

? 5. 在application函數(shù)中姥闭,直接調(diào)用字典丹鸿,通過(guò)訪問(wèn)路徑來(lái)得到對(duì)應(yīng)的響應(yīng)函數(shù)調(diào)用即可

# ------------- 這里開(kāi)始修改代碼1------------

# 創(chuàng)建一個(gè)空字典

router_dict = {}

# ------------- 這里結(jié)束修改代碼1------------

def application(environ, start_response):

? ? # 從服務(wù)器傳過(guò)來(lái)的字典中將訪問(wèn)路徑取出來(lái)

? ? url_path = environ['PATH_INFO']

? ? # 創(chuàng)建一個(gè)路由字典,將訪問(wèn)路徑和響應(yīng)函數(shù)的鍵值對(duì)加入到字典中

? ? # router_dict = {'/index.py': index, '/center.py': center}

? ? # 通過(guò)在路由字典中查找傳入的訪問(wèn)路徑棚品,找到對(duì)應(yīng)的函數(shù)

? ? if url_path in router_dict:

? ? ? ? function = router_dict[url_path]

? ? else:

? ? ? ? function = other

? ? # 執(zhí)行函數(shù)得到數(shù)據(jù)

? ? file_content = function()

? ? # 回調(diào) start_response 函數(shù)靠欢,將響應(yīng)狀態(tài)信息回傳給服務(wù)器

? ? start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

? ? # 返回響應(yīng)數(shù)據(jù)內(nèi)容

? ? return file_content

# ------------- 這里開(kāi)始修改代碼2------------

# 實(shí)現(xiàn)一個(gè)帶參的裝飾器

def router(url_path):

? ? def set_func(func):

? ? ? ? def wrapper(*args,**kwargs):

? ? ? ? ? ? return func(*args,**kwargs)

? ? ? ? #將 wrapper 的引用存入字典入,以 url_path 參數(shù)做為 key,wrapper 指向就是被裝飾函數(shù)本身

? ? ? ? #一定要注意存入的書(shū)寫(xiě)位置,這條語(yǔ)句在執(zhí)行 @set_func 時(shí)執(zhí)行,將鍵值關(guān)系存入字典,否則就錯(cuò)了

? ? ? ? router_dict[url_path] = wrapper

? ? ? ? return wrapper

? ? return set_func

# ------------- 這里結(jié)束修改代碼2------------

# 為每個(gè)函數(shù)添加裝飾器

@router('/index.py')

def index():

? ? pass # 這里功能代碼不需要修改,筆記中省略

@router('/center.py')

def center():

? ? pass # 這里功能代碼不需要修改铜跑,筆記中省略

3.2.9 AOP面向切面編程概念介紹

? <1>什么是AOP面向切面編程:

? ? ? Aspect Oriented Programming AOP面向切面編程

? ? ? 他和面向?qū)ο缶幊桃粯用殴郑彩且环N編程思想。使用 AOP 編程思想锅纺,更利于程序的擴(kuò)展

? ? ? AOP是指在編程過(guò)程中薪缆,開(kāi)發(fā)人員并不關(guān)心這個(gè)程序如何開(kāi)始,如何結(jié)束伞广,只需要關(guān)心,如何添加一個(gè)功能的代碼實(shí)現(xiàn)

? <2>如何實(shí)現(xiàn)AOP編程:

? ? ? 在 python 中疼电,使用裝飾器來(lái)完成AOP編程

? 當(dāng)代碼添加后嚼锄,程序就可以自動(dòng)識(shí)別并運(yùn)行,原理類(lèi)似多米諾骨蔽豺,我們并不關(guān)心從哪開(kāi)始区丑,到哪結(jié)束,我只需要考慮在哪多加一片修陡,加上這片以后,也不影響骨牌的傳遞沧侥。上個(gè)版本的代碼中,使用裝飾器裝飾響應(yīng)函數(shù)魄鸦,基本上就實(shí)現(xiàn)了面向切面編程的思想宴杀。不需要知道程序如何執(zhí)行,只需要在實(shí)現(xiàn)頁(yè)面響應(yīng)功能函數(shù)前加上一個(gè)裝飾器即可拾因。程序在開(kāi)發(fā)過(guò)程中旺罢,并不需要考慮程序運(yùn)行的前因后果旷余,只需要將自己需求的功能實(shí)現(xiàn)在函數(shù)中即可,程序會(huì)自動(dòng)調(diào)用扁达,就像是一張骨牌

3.2.10 SEO 實(shí)現(xiàn)偽靜態(tài)服務(wù)器

? Search Engine Optimization 搜索引擎優(yōu)化:

? ? ? 搜索引擎優(yōu)化是一種利用搜索引擎的搜索規(guī)則來(lái)提高目前網(wǎng)站在有關(guān)搜索引擎內(nèi)的自然排名的方式正卧。

? SEO的目的:

? ? ? 為了從搜索引擎中獲得更多的免費(fèi)流量,從網(wǎng)站結(jié)構(gòu)跪解、內(nèi)容建設(shè)方案炉旷、用戶互動(dòng)傳播、頁(yè)面等角度進(jìn)行合理規(guī)劃叉讥,使網(wǎng)站更適合搜索引擎的索引原則的行為窘行;

? 在搜索時(shí),靜態(tài)頁(yè)面結(jié)果排名比動(dòng)態(tài)頁(yè)面靠前

? ? ? 但是實(shí)際效果不大节吮,顯示在前面的都是競(jìng)價(jià)排名的.花錢(qián)好辦事(比如X田系)

? 為了讓網(wǎng)頁(yè)地址支持SEO,將訪問(wèn)地址中的 xxx.py 改成 xxx.html 的形式

? 在實(shí)際的頁(yè)面訪問(wèn)時(shí),并不會(huì)有 .py 這種格式的文件抽高,所以為了支持SEO,將動(dòng)態(tài)頁(yè)面?zhèn)窝b成靜態(tài)頁(yè)面透绩,將訪問(wèn)地址改為 .html

? 實(shí)現(xiàn)過(guò)程:

? 1. 服務(wù)器文件中用來(lái)判斷文件類(lèi)型的位置要進(jìn)行修改

? 2. 訪問(wèn)地址修改后,數(shù)據(jù)處理文件中相應(yīng)的內(nèi)容也要進(jìn)行修改

? 3. 被裝飾的函數(shù)要修改

? 代碼實(shí)現(xiàn):

? ? ? WebServer.py

#判斷訪問(wèn)路徑的類(lèi)型

if file_name.endswith('.html'):

? WebFrame

# 因?yàn)樵L問(wèn)頁(yè)面變成了 .html 的后綴翘骂,所以裝飾器在傳參的時(shí)候,也需要傳入的是 .html

@set_args('/index.html')

def index():

? ? pass

@set_args('/center.html')

def center():

? ? pass

? 注意: 模板文件中有兩個(gè)用來(lái)實(shí)現(xiàn)頁(yè)面內(nèi)跳轉(zhuǎn)的文件連接帚豪,也是以 .py 文件名進(jìn)行調(diào)用的碳竟,也需要改成 .html

? ? ? index.html文件

? ? ? ? ? ■ <li><a href="/center.html">個(gè)人中心</a></li>

? ? ? center.html文件:

? ? ? ? ? ■ <li><a href="/index.html">個(gè)人中心</a></li>

3.2.11 小結(jié)

至此,我們已經(jīng)完成了MiniWeb框架的編寫(xiě)工作狸臣。

在編程過(guò)程中莹桅,要理解路由,模板等概念烛亦,并且理解使用它們的目的诈泼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市煤禽,隨后出現(xiàn)的幾起案子铐达,更是在濱河造成了極大的恐慌,老刑警劉巖檬果,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓮孙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡选脊,警方通過(guò)查閱死者的電腦和手機(jī)杭抠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恳啥,“玉大人偏灿,你說(shuō)我怎么就攤上這事《鄣模” “怎么了菩混?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵忿墅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我沮峡,道長(zhǎng)疚脐,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任邢疙,我火速辦了婚禮棍弄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疟游。我一直安慰自己呼畸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布颁虐。 她就那樣靜靜地躺著蛮原,像睡著了一般。 火紅的嫁衣襯著肌膚如雪另绩。 梳的紋絲不亂的頭發(fā)上儒陨,一...
    開(kāi)封第一講書(shū)人閱讀 51,274評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音笋籽,去河邊找鬼蹦漠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛车海,可吹牛的內(nèi)容都是我干的笛园。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼侍芝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼研铆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起州叠,我...
    開(kāi)封第一講書(shū)人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤棵红,失蹤者是張志新(化名)和其女友劉穎仅乓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蜒程,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滋饲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疚察。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖可岂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翰灾,我是刑警寧澤缕粹,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布稚茅,位于F島的核電站,受9級(jí)特大地震影響平斩,放射性物質(zhì)發(fā)生泄漏亚享。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一绘面、第九天 我趴在偏房一處隱蔽的房頂上張望欺税。 院中可真熱鬧,春花似錦揭璃、人聲如沸晚凿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)歼秽。三九已至,卻和暖如春情组,著一層夾襖步出監(jiān)牢的瞬間燥筷,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工呻惕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荆责,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓亚脆,卻偏偏與公主長(zhǎng)得像做院,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子濒持,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容