日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Python函數裝飾器的使用教程

瀏覽:34日期:2022-06-17 18:21:39
目錄典型的函數裝飾器疊放裝飾器參數化裝飾器標準庫中的裝飾器functools.wrapsfunctools.lru_cachefunctools.singledispatch小結參考資料:典型的函數裝飾器

以下示例定義了一個裝飾器,輸出函數的運行時間:

Python函數裝飾器的使用教程

函數裝飾器和閉包緊密結合,入參func代表被裝飾函數,通過自由變量綁定后,調用函數并返回結果。

使用clock裝飾器:

import timefrom clockdeco import clock@clockdef snooze(seconds): time.sleep(seconds)@clockdef factorial(n): return 1 if n < 2 else n*factorial(n-1)if __name__==’__main__’: print(’*’ * 40, ’Calling snooze(.123)’) snooze(.123) print(’*’ * 40, ’Calling factorial(6)’) print(’6! =’, factorial(6)) # 6!指6的階乘

輸出結果:

Python函數裝飾器的使用教程

這是裝飾器的典型行為:把被裝飾的函數換成新函數,二者接受相同的參數,而且返回被裝飾的函數本該返回的值,同時還會做些額外操作。

值得注意的是factorial()是個遞歸函數,從結果來看,每次遞歸都用到了裝飾器,打印了運行時間,這是因為如下代碼:

@clockdef factorial(n): return 1 if n < 2 else n*factorial(n-1)

等價于:

def factorial(n): return 1 if n < 2 else n*factorial(n-1) factorial = clock(factorial)

factorial引用的是clock(factorial)函數的返回值,也就是裝飾器內部函數clocked,每次調用factorial(n),執行的都是clocked(n)。

疊放裝飾器

@d1@d2def f(): print('f')

等價于:

def f(): print('f')f = d1(d2(f))參數化裝飾器

怎么讓裝飾器接受參數呢?答案是:創建一個裝飾器工廠函數,把參數傳給它,返回一個裝飾器,然后再把它應用到要裝飾的函數上。

示例如下:

registry = set()def register(active=True): def decorate(func):print(’running register(active=%s)->decorate(%s)’ % (active, func))if active: registry.add(func)else: registry.discard(func)return func return decorate@register(active=False)def f1(): print(’running f1()’)# 注意這里的調用@register()def f2(): print(’running f2()’)def f3(): print(’running f3()’)

register是一個裝飾器工廠函數,接受可選參數active默認為True,內部定義了一個裝飾器decorate并返回。需要注意的是裝飾器工廠函數,即使不傳參數,也要加上小括號調用,比如@register()。

再看一個示例:

import timeDEFAULT_FMT = ’[{elapsed:0.8f}s] {name}({args}) -> {result}’# 裝飾器工廠函數def clock(fmt=DEFAULT_FMT): # 真正的裝飾器 def decorate(func): # 包裝被裝飾的函數def clocked(*_args): t0 = time.time() # _result是被裝飾函數返回的真正結果 _result = func(*_args) elapsed = time.time() - t0 name = func.__name__ args = ’, ’.join(repr(arg) for arg in _args) result = repr(_result) # **locals()返回clocked的局部變量 print(fmt.format(**locals())) return _result return clocked return decorate if __name__ == ’__main__’: @clock() def snooze(seconds):time.sleep(seconds) for i in range(3):snooze(.123)

這是給典型的函數裝飾器添加了參數fmt,裝飾器工廠函數增加了一層嵌套,示例中一共有3個def。

標準庫中的裝飾器

Python內置了三個用于裝飾方法的函數:property、classmethod和staticmethod,這會在將來的文章中講到。本文介紹functools中的三個裝飾器:functools.wraps、functools.lru_cache和functools.singledispatch。

functools.wraps

Python函數裝飾器在實現的時候,被裝飾后的函數其實已經是另外一個函數了(函數名等函數屬性會發生改變),為了不影響,Python的functools包中提供了一個叫wraps的裝飾器來消除這樣的副作用(它能保留原有函數的名稱和函數屬性)。

示例,不加wraps:

def my_decorator(func): def wrapper(*args, **kwargs):’’’decorator’’’print(’Calling decorated function...’)return func(*args, **kwargs) return wrapper@my_decoratordef example(): '''Docstring''' print(’Called example function’)print(example.__name__, example.__doc__)# 輸出wrapper decorator

加wraps:

import functoolsdef my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs):’’’decorator’’’print(’Calling decorated function...’)return func(*args, **kwargs) return wrapper@my_decoratordef example(): '''Docstring''' print(’Called example function’)print(example.__name__, example.__doc__)# 輸出example Docstringfunctools.lru_cache

lru是Least Recently Used的縮寫,它是一項優化技術,把耗時的函數的結果保存起來,避免傳入相同的參數時重復計算。

示例:

import functoolsfrom clockdeco import clock@functools.lru_cache()@clockdef fibonacci(n): if n < 2:return n return fibonacci(n-2) + fibonacci(n-1)if __name__==’__main__’: print(fibonacci(6))

優化了遞歸算法,執行時間會減半。

注意,lru_cache可以使用兩個可選的參數來配置,它的簽名如下:

functools.lru_cache(maxsize=128, typed=False) maxsize:最大存儲數量,緩存滿了以后,舊的結果會被扔掉。 typed:如果設為True,那么會把不同參數類型得到的結果分開保存,即把通常認為相等的浮點數和整型參數(如1和1.0)區分開。functools.singledispatch

Python3.4的新增語法,可以用來優化函數中的大量if/elif/elif。使用@singledispatch裝飾的普通函數會變成泛函數:根據第一個參數的類型,以不同方式執行相同操作的一組函數。所以它叫做single dispatch,單分派。

根據多個參數進行分派,就是多分派了。

示例,生成HTML,顯示不同類型的Python對象:

import htmldef htmlize(obj): content = html.escape(repr(obj)) return ’<pre>{}</pre>’.format(content)

因為Python不支持重載方法或函數,所以就不能使用不同的簽名定義htmlize的變體,只能把htmlize變成一個分派函數,使用if/elif/elif,調用專門的函數,比如htmlize_str、htmlize_int等。時間一長htmlize會變得很大,跟各個專門函數之間的耦合也很緊密,不便于模塊擴展。

@singledispatch經過深思熟慮后加入到了標準庫,來解決這類問題:

from functools import singledispatchfrom collections import abcimport numbersimport html@singledispatchdef htmlize(obj): # 基函數 這里不用寫if/elif/elif來分派了 content = html.escape(repr(obj)) return ’<pre>{}</pre>’.format(content)@htmlize.register(str)def _(text): # 專門函數 content = html.escape(text).replace(’n’, ’<br>n’) return ’<p>{0}</p>’.format(content)@htmlize.register(numbers.Integral) def _(n): # 專門函數 return ’<pre>{0} (0x{0:x})</pre>’.format(n)@htmlize.register(tuple)@htmlize.register(abc.MutableSequence)def _(seq): # 專門函數 inner = ’</li>n<li>’.join(htmlize(item) for item in seq) return ’<ul>n<li>’ + inner + ’</li>n</ul>’

@singledispatch裝飾了基函數。專門函數使用@<<base_function>>.register(<<type>>)裝飾,它的名字不重要,命名為_,簡單明了。

這樣編寫代碼后,Python會根據第一個參數的類型,調用相應的專門函數。

小結

本文首先介紹了典型的函數裝飾器:把被裝飾的函數換成新函數,二者接受相同的參數,而且返回被裝飾的函數本該返回的值,同時還會做些額外操作。接著介紹了裝飾器的兩個高級用法:疊放裝飾器和參數化裝飾器,它們都會增加函數的嵌套層級。最后介紹了3個標準庫中的裝飾器:保留原有函數屬性的functools.wraps、緩存耗時的函數結果的functools.lru_cache和優化if/elif/elif代碼的functools.singledispatch。

參考資料:

《流暢的Python》https://github.com/fluentpython/example-code/tree/master/07-closure-deco

https://blog.csdn.net/liuzonghao88/article/details/103586634

以上就是Python函數裝飾器高級用法的詳細內容,更多關于Python函數裝飾器用法的資料請關注好吧啦網其它相關文章!

標簽: Python 編程
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
91精品xxx在线观看| 私拍精品福利视频在线一区| 精品久久福利| 日本va欧美va精品发布| 亚洲一区二区免费看| 色网在线免费观看| 久久精品国产福利| 91成人精品观看| 欧美亚洲tv| 精品视频在线一区二区在线| 麻豆精品在线观看| 亚洲精品**中文毛片| 人人香蕉久久| 亚洲一区二区免费看| 石原莉奈一区二区三区在线观看| 日本不卡一二三区黄网| 欧美日本不卡高清| 日韩毛片视频| 午夜久久黄色| 亚洲精品美女| 国产中文字幕一区二区三区| 亚洲a一区二区三区| 黄色aa久久| 国产午夜久久| 欧美精品第一区| 日韩欧美字幕| 亚洲专区视频| 91综合视频| 亚洲影视一区二区三区| 国产精选一区| 国产高清一区| 国产欧美一区二区色老头| 国产精品精品| 日韩在线观看一区二区| 国产激情欧美| 激情婷婷久久| 国产精品久久久久av蜜臀| 欧美亚洲综合视频| 久久五月天小说| 日本精品另类| 99久久久久| 日本少妇精品亚洲第一区| 久久久久久一区二区| 亚洲免费影视| 精品中国亚洲| 亚洲精品少妇| 日韩理论视频| 日本麻豆一区二区三区视频| 9999国产精品| 亚洲毛片一区| 亚洲1234区| 国产免费av国片精品草莓男男| 国产欧美日韩精品一区二区三区| 色88888久久久久久影院| 亚洲精品高潮| 99久久亚洲精品| 国产精品美女午夜爽爽| 视频一区中文| 91欧美日韩| 日韩福利在线观看| 五月天久久久| 麻豆视频在线观看免费网站黄| 日韩精品久久久久久久软件91| 久久久久午夜电影| 国产精品多人| 日韩三级精品| 午夜欧美理论片| 欧美中文高清| 久久成人国产| 亚洲综合在线电影| 国产精品极品| 日本欧美在线| 蜜桃av一区二区在线观看| 久久电影tv| 日本午夜精品久久久久| 国产精品日本欧美一区二区三区| 久久久久伊人| 日本久久一区| 亚洲伊人精品酒店| 999久久久亚洲| 国产精品13p| 国产美女亚洲精品7777| 亚洲免费精品| 青青久久av| 国内精品麻豆美女在线播放视频| 日韩福利视频网| 四虎成人精品一区二区免费网站| 亚洲特色特黄| 久久亚洲国产| 亚洲综合在线电影| 激情国产在线| 麻豆视频在线观看免费网站黄| 国产精品玖玖玖在线资源| 日韩三级久久| 日韩久久一区| 日精品一区二区三区| 亚洲欧美日韩精品一区二区| 激情视频网站在线播放色| 久久不卡国产精品一区二区| 国产日韩欧美| 国产精品一页| 久久不见久久见免费视频7| **爰片久久毛片| 日韩一区免费| 国产日韩欧美| 久久精品一区二区国产| 欧美激情综合| 97国产成人高清在线观看| 国产精品99视频| 欧美不卡高清一区二区三区| 久久精品观看| 亚洲在线电影| 一区福利视频| 日av在线不卡| 日韩不卡免费视频| 久久久免费人体| 五月激情久久| 欧美资源在线| 欧美一区网站| 黄色在线网站噜噜噜| 欧美日韩一区二区三区视频播放| 黑丝一区二区| 日韩高清不卡一区二区| 久久精品国产99国产| 天堂√8在线中文| 日韩视频二区| 欧美日韩在线精品一区二区三区激情综合| 亚洲精品无播放器在线播放| 日韩毛片网站| 国产精品久久观看| 亚洲国产专区校园欧美| 免费在线观看成人| 麻豆高清免费国产一区| 在线天堂中文资源最新版| 久久一级电影| 日韩三区四区| 精品少妇av| 秋霞影院一区二区三区| 久久不射网站| 久久中文字幕一区二区| 精品一区不卡| 亚洲高清成人| 每日更新成人在线视频| 日本综合视频| 成人午夜在线| 在线视频亚洲| 日本成人在线视频网站| 欧美亚洲综合视频| 91亚洲国产| 视频在线观看一区二区三区| 亚洲人成高清| 精品国产a一区二区三区v免费| 日本欧美不卡| 蜜桃视频免费观看一区| 国内揄拍国内精品久久| 五月精品视频| 日本欧美韩国一区三区| 国产精品视频首页| 国产综合亚洲精品一区二| 视频在线在亚洲| 国产精品天天看天天狠| 欧美一区二区性| 国产精品欧美一区二区三区不卡| 精品视频亚洲| 日韩在线观看一区二区| 玖玖玖国产精品| 精品深夜福利视频| 狠狠色综合网| 久久三级中文| 午夜宅男久久久| 国产精品主播| 久久精品国产99久久| 亚洲精品黄色| 国产精品久久亚洲不卡| 日韩在线欧美| 男人的天堂久久精品| 欧美亚洲三级| 黄色在线网站噜噜噜| 亚洲一区激情| 国产精品久久| 国产精品毛片一区二区三区| 久久精品99国产精品日本| 日韩黄色大片| 国产精品99久久久久久董美香| 免费污视频在线一区| 免费视频久久| 精品国产欧美日韩| 三上悠亚国产精品一区二区三区| 欧美综合国产| a国产在线视频| 视频精品一区| 成人羞羞在线观看网站| 青青草国产成人99久久| 色88888久久久久久影院| 日本综合精品一区| 99在线|亚洲一区二区| 麻豆精品久久久| 三级欧美韩日大片在线看| 精品国产欧美日韩| 免费一区二区视频|