中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

怎么用Python編寫(xiě)一個(gè)裝飾器

本篇內(nèi)容主要講解“怎么用Python編寫(xiě)一個(gè)裝飾器”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“怎么用Python編寫(xiě)一個(gè)裝飾器”吧!

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序制作、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了杞縣免費(fèi)建站歡迎大家使用!

首先概念,裝飾器是閉包的一種應(yīng)用,需要滿足一下規(guī)則:

1.在不更改原功能函數(shù)的內(nèi)部代碼,并且改變調(diào)用方法的情況下為原函數(shù)增加新功能

2.遵循開(kāi)放封閉原則,什么是開(kāi)放封閉原則呢?

a.已實(shí)現(xiàn)的功能可以添加或擴(kuò)展新的功能(開(kāi)放原則)

b.不修改已實(shí)現(xiàn)功能的內(nèi)部代碼(封閉原則)

其次作用,登錄驗(yàn)證、函數(shù)運(yùn)行時(shí)長(zhǎng)統(tǒng)計(jì)、執(zhí)行函數(shù)之前做的準(zhǔn)備工作,執(zhí)行函數(shù)之后清理功能,總之你能想到的擴(kuò)展功能大部分都可以實(shí)現(xiàn),而且是在原功能代碼不做修改的情況下就可以優(yōu)雅的完成!

一起來(lái)看下裝飾器的實(shí)踐,親身經(jīng)歷的問(wèn)題!因?yàn)楣ぷ鳟?dāng)中經(jīng)常性需要獲取接口數(shù)據(jù),所以就簡(jiǎn)單的封裝了一個(gè)獲取數(shù)據(jù)的方法,代碼如下:

import requests
import re
def send_request_by(method, url, data):
 """
 請(qǐng)求接口獲取數(shù)據(jù)
 :param method: 發(fā)起請(qǐng)求的方式
 :param url: 請(qǐng)求地址
 :param data: 請(qǐng)求數(shù)據(jù)
 :return:
 """
 if re.match("POST", method, flags=re.IGNORECASE):
 response = requests.post(url, data=data)
 if re.match("GET", method, flags=re.IGNORECASE):
 response = requests.get(url, data=data)
 return response

目前看來(lái)對(duì)自己的需求已經(jīng)滿足,但是每次請(qǐng)求的時(shí)候發(fā)現(xiàn)還是報(bào)錯(cuò)!最終通過(guò)抓包工具分析發(fā)現(xiàn),在客戶端進(jìn)行接口調(diào)用的時(shí)都多了一個(gè)"sign"字段,這個(gè)字段是怎么來(lái)的呢?經(jīng)過(guò)分析"sign"是在加密后得來(lái)的,為了解決這個(gè)問(wèn)題對(duì)代碼進(jìn)行了一次改造,代碼如下:

def send_request_by(method, url, data):
 md5_pwd = MD5Password()
 data['sign'] = md5_pwd(data)
 if re.match("POST", method, flags=re.IGNORECASE):
 response = requests.post(url, data=data)
 if re.match("GET", method, flags=re.IGNORECASE):
 response = requests.get(url, data=data)
 return response

這樣看起來(lái)是解決了問(wèn)題,但其實(shí)沒(méi)有靈活的解決問(wèn)題。試問(wèn),如果哪天又不需要加密簽名是不是還得把新加的兩行代碼干掉?那怎么能不修改原功能又能添加加密的功能呢。經(jīng)過(guò)和大佬討教之后,發(fā)現(xiàn)可以通過(guò)裝飾器來(lái)實(shí)現(xiàn),再一次對(duì)代碼進(jìn)行了改造,代碼如下:

def sign_md5(func):
 def wrapper(*args, **kwargs):
 if not kwargs.get('data'):
 raise KeyError("not found Key 'data'")
 if kwargs.get('data') is None:
 raise ValueError(f'{kwargs.get("data")} of value is None')
 # 首字母排序
 sort_data = json.loads(json.dumps(kwargs.get('data'), sort_keys=True))
 # 私有加密規(guī)則,生成簽名
 md5_pwd = MD5Password()
 sign = md5_pwd(sort_data)
 sort_data['sig'] = sign
 kwargs['data'] = sort_data
 ret = func(*args, **kwargs)
 return ret
 return wrapper
 @sign_md5 # send_request_by = sign_md5(send_request_by)
 def send_request_by(method, url, data):
 # md5_pwd = MD5Password()
 # data['sign'] = md5_pwd(data)
 if re.match("POST", method, flags=re.IGNORECASE):
 response = requests.post(url, data=data)
 if re.match("GET", method, flags=re.IGNORECASE):
 response = requests.get(url, data=data)
 return response

經(jīng)過(guò)測(cè)試之后發(fā)現(xiàn),非常靈活的解決問(wèn)題,不需要加密的時(shí)候注釋掉@sign_md5即可!那么這個(gè)@sign_md5到底做了什么?

其實(shí)質(zhì)就是在沒(méi)有使用"@"魔法的情況下是sign_md5(send_request_by)(method, ulr, data),而當(dāng)使用"@"魔法進(jìn)行裝飾后,代碼執(zhí)行到此行時(shí)解析器會(huì)將被裝飾的send_request_by作為一個(gè)參數(shù)傳遞給sign_md5,即send_request_by這個(gè)函數(shù)已經(jīng)作為變量傳遞給了sign_md(func)中的func參數(shù),并返回了wrapper這個(gè)函數(shù),在接下來(lái)調(diào)用send_request_by(method, url, data)這個(gè)函數(shù),其實(shí)此時(shí)send_request_by已經(jīng)不是原先的def send_request_by(method, url, data)中的send_request_by,而是指向了wrapper(*args, **kwargs)這個(gè)函數(shù)。wrapper這個(gè)函數(shù)接收任意參數(shù),所以當(dāng)執(zhí)行send_request_by(method, url, data)函數(shù)時(shí),其實(shí)把method, url, data參數(shù)傳遞給warpper函數(shù),并執(zhí)行wrapper內(nèi)部代碼,而wrapper函數(shù)內(nèi)部的func就是我們傳入的send_request_by函數(shù)了,意思可以理解為,我們將參數(shù)傳給了wrapper函數(shù),在wrapper函數(shù)內(nèi)將請(qǐng)求參數(shù)進(jìn)行加密后,傳遞給了send_request_by函數(shù)進(jìn)行請(qǐng)求,從而在請(qǐng)求之前完成了加密的過(guò)程。而wrapper函數(shù)內(nèi)func(*args, **kwargs)指向的是send_request_by(method, url, data)而ret也就是send_request_by(method, url, data)函數(shù)的返回結(jié)果,因此將ret返回出來(lái)。這塊比較繞口,多捋一捋相信憑你的聰明才智一定會(huì)明白!到時(shí)你一定會(huì)認(rèn)為,哇!竟然如此簡(jiǎn)單!?。《酱藶橹?,最簡(jiǎn)單的無(wú)參數(shù)裝飾器就此完成!領(lǐng)導(dǎo)一定會(huì)夸你,秀兒!

那么,在解決了這個(gè)需求之后自己又有了新的疑惑,如果哪天開(kāi)發(fā)不按照字段首字母排序了,我該怎么辦????是不是又要重新寫(xiě)裝飾器了???那有什么辦法能在裝飾器內(nèi)控制是否排序呢?那么也是經(jīng)過(guò)各種腦補(bǔ),又又又進(jìn)行了一次代碼的修改,代碼如下:

def sign_sort(sort=True):
 def sign_md5(func):
 def wrapper(*args, **kwargs):
 if not kwargs.get('data'):
 raise KeyError("not found Key 'data'")
 if kwargs.get('data') is None:
 raise ValueError(f'{kwargs.get("data")} of value is None')
 # sort 參數(shù)控制是否按首字母排序
 sort_data = json.dumps(kwargs.get('data'), sort_keys=True) if sort else json.dumps(kwargs.get('data'))
 sort_data = json.loads(sort_data)
 # 私有加密規(guī)則,生成簽名
 md5_pwd = MD5Password()
 sign = md5_pwd(sort_data)
 sort_data['sig'] = sign
 kwargs['data'] = sort_data
 ret = func(*args, **kwargs)
 return ret
 return wrapper
 return sign_md5
@sign_sort(sort=True) # send_request_by = sign_sort(sort=Ture)(send_request_by)
def send_request_by(method, url, data):
 print(data)
 if re.match("POST", method, flags=re.IGNORECASE):
 response = requests.post(url, data=data)
 elif re.match("GET", method, flags=re.IGNORECASE):
 response = requests.get(url, data=data)
 return respons

那這一次是做了哪些優(yōu)化呢?其實(shí)還是在學(xué)習(xí)無(wú)參裝飾器的基礎(chǔ)之上學(xué)習(xí)了一下帶參數(shù)裝飾器。仍然還是不變的。我們一起來(lái)分析一下,

首先來(lái)看sign_sort(sort=True),sign_sort實(shí)質(zhì)是一個(gè)函數(shù)接收一個(gè)參數(shù),并返回sign_md5函數(shù)。

當(dāng)代碼執(zhí)行到"@"所在行時(shí),同樣會(huì)把被裝飾send_request_by函數(shù)作為一個(gè)參數(shù)傳遞給sign_sort(sort=True)函數(shù)的調(diào)用結(jié)果(即sign_md5)。

也就是說(shuō)send_request_by函數(shù)又是作為一個(gè)變量(函數(shù)也可以是變量)傳遞給了sign_md5函數(shù)中的func參數(shù),并返回了一個(gè)wrapper函數(shù)。

在后面調(diào)用send_request_by(method, url, data)函數(shù)時(shí),同樣此時(shí)的send_request_by已經(jīng)不再是def send_request_by(method, url, data)函數(shù)中的send_request_by,而是wrapper(*args, **kwargs)函數(shù)。

wrapper函數(shù)接收任意參數(shù),所以當(dāng)執(zhí)行send_request_by(method, url, data)時(shí),會(huì)把method, url, data傳遞給wrapper函數(shù),執(zhí)行wrapper函數(shù)內(nèi)的代碼,而wrapper內(nèi)部的func(*args, **kwargs)還是指向send_request_by,可以理解為通過(guò)wrapper函數(shù)將參數(shù)傳遞給send_request_by函數(shù),而在傳遞給send_request_by之前,我們可以對(duì)參數(shù)做任意的操作,因此我在傳遞之前判斷了sort參數(shù)是否為True作為排序的開(kāi)關(guān),再對(duì)請(qǐng)求數(shù)據(jù)data進(jìn)行加密的操作,最后帶著加密簽名傳遞給send_request_by函數(shù)進(jìn)行發(fā)送請(qǐng)求。

到此,相信大家對(duì)“怎么用Python編寫(xiě)一個(gè)裝飾器”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

標(biāo)題名稱:怎么用Python編寫(xiě)一個(gè)裝飾器
文章轉(zhuǎn)載:http://www.rwnh.cn/article18/jdjjgp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、品牌網(wǎng)站設(shè)計(jì)、微信公眾號(hào)、域名注冊(cè)、虛擬主機(jī)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
怀柔区| 周口市| 永修县| 白朗县| 洞头县| 廊坊市| 申扎县| 淮安市| 曲麻莱县| 池州市| 盐边县| 高要市| 准格尔旗| 梁山县| 正蓝旗| 东方市| 钦州市| 榆社县| 东乡族自治县| 莒南县| 土默特右旗| 张家港市| 五台县| 班玛县| 搜索| 柳河县| 兴隆县| 饶河县| 建德市| 乌审旗| 邳州市| 新密市| 吉安县| 勃利县| 贵州省| 永安市| 荆门市| 岳普湖县| 博罗县| 梓潼县| 关岭|