国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

python學(xué)習(xí)筆記(30)--元編程1-裝飾器

2019-11-08 02:40:59
字體:
供稿:網(wǎng)友

軟件開發(fā)的過程中,最基本的技能就是:不要重復(fù)自己的工作。也就是說,在任何時候,當(dāng)需要創(chuàng)建高度重復(fù)的代碼時,通常都需要尋找一個更加快捷的解決方案。在python中,這類問題常常會歸為“元編程”。 簡而言之,元編程的主要目標(biāo)是創(chuàng)建函數(shù)和類,并用他們來操縱代碼(通常的行為有生成、修改、包裝已有的代碼)。Python中基于這個目的的方法有裝飾器、類裝飾器、元類以及有用的主題(常見的有對象簽名、用exec()來執(zhí)行代碼以及檢查函數(shù)和類的內(nèi)部結(jié)構(gòu))。 元編程系列主要內(nèi)容是探討各種元編程技術(shù),通過實例來講解如何利用這些技術(shù)來自定義python的行為,使其能滿足我們不同尋常的需求。

1 裝飾器

1.1 用裝飾器給函數(shù)添加一個包裝

裝飾器的本質(zhì)就是一個函數(shù),它可以接受一個函數(shù)作為輸入并返回一個新的函數(shù)作為輸出。我們可以利用給函數(shù)來建立一個裝飾器(相當(dāng)于給函數(shù)加上包裝層)來添加額外的處理,例如記錄日志、計時統(tǒng)計等。 最簡單的一個例子是計時系統(tǒng),我想記錄函數(shù)的運行時間并打印到控制臺,最通常的做法是:

def CutDown(n): import time start = time.time() while n > 0: n -= 1 end = time.time() PRint(end-start)CutDown(10000000)屏幕輸出:1.1250569820404053

下面引入裝飾器方法:

def GetRunTime(func): import time from functools import wraps @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(func.__name__, end - start) return result return wrapper@GetRunTimedef cutdown(n): while n > 0: n -= 1cutdown(10000000)屏幕輸出:cutdown 1.1274616718292236

用第二種方法的好處就是,加入我需要在很多的函數(shù)上記錄其運行時間,則只需要在需要記錄時間的函數(shù)上面添加@GetRunTime即可,調(diào)試非常方便,代碼也簡潔易懂。 裝飾器內(nèi)部的代碼一般會涉及創(chuàng)建一個新的函數(shù),利用*args和**kwargs來接受任意的參數(shù),在示例中wrapper()函數(shù)就是這么操作的。在這個函數(shù)的內(nèi)部,我們需要調(diào)用原來的輸入?yún)?shù)(即被包裝的函數(shù)的輸入?yún)?shù))并返回它的結(jié)果。 其實運行過程就是將被裝飾函數(shù)打包到裝飾器中運行并返回運行結(jié)果,作為代價肯定是需要犧牲一定的效率的。 在示例中還有一個是需要注意的,那就是@wraps(func),它用來保存函數(shù)的元數(shù)據(jù)。其實也可以不要這個,但是就會丟失被裝飾函數(shù)的一些元數(shù)據(jù),例如函數(shù)名、文檔字符串、函數(shù)注解以及調(diào)用簽名。1.2就會講解如何保存元數(shù)據(jù)。

1.2 運用裝飾器時保存函數(shù)的元數(shù)據(jù)

在1.1中也提到過,即使沒有@wraps(func)函數(shù)也能運行,代價是丟失一些函數(shù)的元數(shù)據(jù):

def GetRunTime(func): import time #from functools import wraps # @wraps(func) def wrapper(*args, **kwargs): """ :param args: :param kwargs: :return: """ start = time.time() result = func(*args, **kwargs) end = time.time() print(func.__name__, end - start) return result return wrapper@GetRunTimedef cutdown(n): """ :param n: :return: """ while n > 0: n -= 1cutdown(10000000)print(cutdown.__name__)print(cutdown.__doc__)

控制臺打印信息:

cutdown 1.4844520092010498wrapper :param args: :param kwargs: :return:

我們發(fā)現(xiàn)打印信息不是cundown這個函數(shù)的,而是裝飾器函數(shù)的。再使用@wraps(func)這個技術(shù): (代碼略) 控制臺打印信息:

cutdown 1.193265676498413cutdown :param n::return:

這個時候所有信息都屬于cutdown函數(shù)的。 上面這個例子告訴我們,在我們自己編寫裝飾器的時候一定要記得使用@wraps(func),這樣才不會丟失被裝飾函數(shù)的元數(shù)據(jù)。同時,從這個例子中我們也可以看到被裝飾函數(shù)的運行過程,裝飾器會接管被裝飾函數(shù)的所有,并返回結(jié)果。 @裝飾器的重要特性就是它可以通過wrapped屬性來訪問被包裝的函數(shù),所以我們可以利用這個特性來解包。

1.3 對裝飾器進行解包

在1.2的末尾也提到過,利用wrapped屬性來進行解包。例如在1.2中可以直接使用:

@GetRunTimedef cutdown(n): """ :param n: :return: """ print('cundown is running') while n > 0: n -= 1cutdown.__wrapped__(10000000)打印輸出:cundown is running

當(dāng)有多個裝飾器的函數(shù)也可以通過這種方法來訪問。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 都江堰市| 岢岚县| 赤壁市| 宁海县| 安化县| 成都市| 陇川县| 苏尼特左旗| 华亭县| 达日县| 沂源县| 东安县| 抚顺县| 宁阳县| 石景山区| 宣恩县| 嘉兴市| 同江市| 隆回县| 栾城县| 庆阳市| 屏山县| 安多县| 许昌市| 辽中县| 宝鸡市| 红原县| 濮阳县| 赞皇县| 临邑县| 陇西县| 商都县| 富顺县| 环江| 衡阳县| 桑日县| 鲁山县| 惠东县| 徐闻县| 富锦市| 阜康市|