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

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

Python函數裝飾器的使用教程

瀏覽:38日期: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久久,三上悠亚国产精品一区二区三区
日韩精品亚洲aⅴ在线影院| 欧美日韩激情| 日韩三级久久| 亚洲一区二区小说| 另类av一区二区| 日韩一区二区免费看| a国产在线视频| 国产在线|日韩| 五月精品视频| 西西人体一区二区| 亚洲精品麻豆| 欧美中文一区| 久久激情av| 欧美aa在线视频| 福利一区和二区| 亚洲精品在线国产| 欧美一区久久久| 日韩欧美一区免费| 午夜欧美视频| 最新国产精品| 91亚洲无吗| 欧美黄页在线免费观看| 国产精品久久久久久久久妇女| 日韩不卡一二三区| 亚洲一级少妇| 99久久久久| 亚洲专区视频| 免费av一区| 蜜臀久久99精品久久久画质超高清 | 欧美在线资源| 在线午夜精品| 日韩一区二区三区四区五区| 久久伊人亚洲| 久久精品免费一区二区三区| 久久亚洲二区| 免费日韩成人| 国产一区二区中文| 少妇精品久久久一区二区| 国产一区日韩一区| 国产视频一区在线观看一区免费| 精品日韩视频| 美女免费视频一区| 日韩理论片av| 综合欧美精品| 国产精品蜜芽在线观看| 99国产精品久久久久久久成人热 | 日韩成人一级| 成人在线视频免费看| 亚洲免费影视| 精品视频一区二区三区四区五区| 国产日韩三级| 最新中文字幕在线播放| 国产女优一区| 精品视频99| 亚洲一区二区免费看| 免费一级欧美在线观看视频| 国产在线日韩| 国产日韩欧美高清免费| 日韩精品午夜| 日韩国产在线观看| 日韩精品亚洲专区| 国产精品久久久久久久久久10秀| 国产videos久久| 亚洲一区国产一区| 欧美激情在线精品一区二区三区| 国产麻豆一区| 伊人久久高清| 欧美亚洲色图校园春色| 91成人精品| 久久亚洲精品中文字幕| 视频在线观看国产精品| 日韩欧美三级| 国产视频网站一区二区三区| 中文亚洲欧美| 国产66精品| 97在线精品| 欧美aa在线观看| 欧美三级第一页| 国产精品三上| 999国产精品视频| 另类小说一区二区三区| 国产一区丝袜| 中文字幕一区二区av| 日韩综合小视频| 蜜臀国产一区| 久久精品二区亚洲w码| 亚洲精品福利| 伊人精品视频| аⅴ资源天堂资源库在线| 日韩av一级片| 老牛影视一区二区三区| 99视频精品视频高清免费| 久久久免费人体| 国产日产一区| 97精品在线| 国产欧美一区二区三区国产幕精品 | 视频一区二区中文字幕| 日本精品在线中文字幕| 国产精品巨作av| 午夜精品福利影院| 在线亚洲免费| 亚洲精品在线观看91| 黄色aa久久| 精品中文在线| 久久av中文| 欧美日韩一区二区三区不卡视频| 成人亚洲一区| 国产精品网在线观看| 日韩1区2区3区| 日韩精品91| 免费在线亚洲| 另类综合日韩欧美亚洲| 性欧美69xoxoxoxo| 色婷婷综合网| 91亚洲国产成人久久精品| 九九99久久精品在免费线bt| 欧美激情亚洲| 欧美国产极品| 麻豆一区在线| 久久精品九色| 国产一区二区久久久久| 久久精品国产99国产精品| 麻豆国产精品视频| 久久精品国产亚洲一区二区三区| 亚洲激情二区| 欧美亚洲国产精品久久| 亚洲精品在线影院| 午夜精品影视国产一区在线麻豆| 欧美激情91| 欧美黄色一区二区| 国产一区二区三区91| 天堂√8在线中文| 激情久久五月| 免费日韩一区二区| 亚洲乱码久久| 欧美日韩伊人| 九九久久国产| 日韩专区精品| 最新日韩欧美| 亚洲日产国产精品| 91欧美极品| 国产高清日韩| 色婷婷综合网| 精品成人免费一区二区在线播放| 国产精品一区二区99| 国产高清视频一区二区| 日产精品一区二区| 日韩av二区在线播放| 国产图片一区| 一区二区91| 日日夜夜免费精品视频| 国产精品美女久久久久久不卡| 中文字幕一区二区三区四区久久| 四季av一区二区凹凸精品| 麻豆成全视频免费观看在线看| 国产日产精品_国产精品毛片 | 麻豆精品蜜桃视频网站| 国模大尺度视频一区二区| 色在线中文字幕| 中文在线不卡| 日本aⅴ精品一区二区三区| 久久久国产精品网站| 中文字幕系列一区| 亚洲一区欧美二区| 日韩精品a在线观看91| 国产精品久久久一区二区| 日韩免费看片| 亚洲尤物在线| 国产精品宾馆| 久久一区二区中文字幕| 一区二区精彩视频| 精品一区二区男人吃奶 | 亚洲精品第一| 美女精品久久| 国产欧美精品| 日韩欧美2区| 日本不卡免费高清视频在线| 亚洲欧美激情诱惑| 国产精品免费99久久久| 日韩精品欧美| 日韩av一区二区在线影视| 日韩精品电影| 青青草伊人久久| 亚洲午夜黄色| 国产精品极品国产中出| 久久国产中文字幕| 国产日产高清欧美一区二区三区 | 精品伊人久久久| 红桃视频亚洲| 国内精品伊人| 亚洲理论在线| av综合电影网站| 日本特黄久久久高潮| 亚洲h色精品| 国产精品久久乐| 亚洲一区欧美二区| 国产 日韩 欧美 综合 一区| 日产午夜精品一线二线三线| 亚洲二区三区不卡| 精品国产一区二区三区噜噜噜|