functools模塊

一.update_wrapper

該函數(shù)用于更新包裝函數(shù)(wrapper),使它看起來像被包裝的原函數(shù)一樣。
該函數(shù)主要用于裝飾器函數(shù)的定義中,置于包裝函數(shù)之前。如果沒有對包裝函數(shù)進(jìn)行更新,那么被裝飾后的函數(shù)所具有的元信息就會變?yōu)榘b函數(shù)的元信息,而不是原函數(shù)的元信息。

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',  '__annotations__')
WRAPPER_UPDATES = ('__dict__',)
update_wrapper(wrapper,
               wrapped,
               assigned = WRAPPER_ASSIGNMENTS,
               updated = WRAPPER_UPDATES):
  • wrapper 包裝函數(shù),被更新者
  • wrapped 被包裝函數(shù),數(shù)據(jù)源
  • assigned 包裝函數(shù)需要替換的屬性,替換的內(nèi)容直接來自于被包裝函數(shù)
  • updated 指定包裝函數(shù)需要更新的屬性,更新的內(nèi)容需要對照被包裝函數(shù)進(jìn)行更新。

該函數(shù)自動在wrapper函數(shù)添加一個wrapped屬性,保留著wrapped函數(shù)

import datetime, time, functools
def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
    def _logger(fn):
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            ret = fn(*args,**kwargs)
            delta = (datetime.datetime.now() - start).total_seconds() 
            if delta > duration:
                func(fn.__name__, duration) 
            return ret
        return functools.update_wrapper(wrapper, fn) 
    return _logger
@logger(5) # add = logger(5)(add) 
def add(x,y):
    time.sleep(1) 
    return x + y
print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='\n')

二.functools.wraps

def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):

    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)

這是一個便捷函數(shù),定義一個wrapper函數(shù)時,作為函數(shù)裝飾器調(diào)用update_wrapper()。它等價于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated),返回一個形參wrapped 有默認(rèn)值的新的update_warpper 函數(shù)

import datetime, time, functools
def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
    def _logger(fn):
        @functools.wraps(fn)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            ret = fn(*args,**kwargs)
            delta = (datetime.datetime.now() - start).total_seconds() 
            if delta > duration:
                func(fn.__name__, duration) 
            return ret
        return wrapper
    return _logger
@logger(5) # add = logger(5)(add) 
def add(x,y):
    time.sleep(1) 
    return x + y
print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='\n')

三.functools.reduce

reduce(function, sequence, initial=None) -> value

  • function 這個函數(shù)是要有兩個參數(shù)的
  • sequence 序列
  • initial 如果初始值沒有,拿sequence第一個元素

等價于

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    for element in it:
        value = function(value, element)
    return value

具體應(yīng)用如下:

from functools import reduce
def add(x,y):
    return x + y
reduce(add,range(5))

四.functools.partial 偏函數(shù)

functools.partial(func, *args, **keywords) -> newfunc
把函數(shù)部分的參數(shù)固定下來,相當(dāng)于為部分的參數(shù)添加了一個固定的默認(rèn)值,形成一個新的函數(shù)并且返回,是對原函數(shù)的封裝
partial 函數(shù)本質(zhì)

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords): # 包裝函數(shù)
        newkeywords = keywords.copy() newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
newfunc.func = func # 保留原函數(shù)
newfunc.args = args # 保留原函數(shù)的位置參數(shù) 
newfunc.keywords = keywords # 保留原函數(shù)的關(guān)鍵字參數(shù)參數(shù) 
return newfunc

五.functools.lru_cache

functools.lru_cache(maxsize=128, typed=False)

  • Least-recently-used 裝飾器。
  • 如果maxsize 設(shè)置為None,則金庸LRU功能,并且緩存可以無限制增長,當(dāng)maxsize是2的冪的時候,LRU功能執(zhí)行最好
  • 如果typed為True,則不同類型的函數(shù)參數(shù)將單獨緩存,例如,f(3)和f(3.0)將被視為具有同結(jié)果的不同調(diào)用
  • 使用前提
    1.同樣的函數(shù)參數(shù)一定得到同樣的結(jié)果
    2.函數(shù)執(zhí)行時間很長,且要多次執(zhí)行
  • 本質(zhì)是函數(shù)調(diào)用的參數(shù) ->返回值
  • 缺點
    1. 不支持緩存過期,key無法過期,失效
    2. 不支持清除操作
    3. 不支持分布式,是一個單機的緩存
  • 使用場景,單機上需要空間換時間的地方,可以用緩存來將計算變成快速的查詢

裝飾器用一個有記憶的調(diào)用包裝一個函數(shù),它可以保存最近maxsize次調(diào)用。當(dāng)使用同樣的參數(shù)定期調(diào)用費時或I/O綁定的函數(shù)時,它可以節(jié)省時間。
因為使用字典緩存結(jié)果,所以函數(shù)的位置和關(guān)鍵字必須是可以哈希的。
為了幫助測量緩存的有效性并且調(diào)整maxsize 參數(shù),可以使用cache_info() 返回一個命名元組,包含hits,misses,maxsize和currsize。在多線程環(huán)境中,hits和misses是近似值。
裝飾器還提供了cache_clean() 用于清除緩存。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 functools函數(shù) functools模塊用于高階函數(shù):作用與或者返回其它函數(shù)的函數(shù)。一般來說,對于該模塊...
    lakerszhy閱讀 10,106評論 0 7
  • functools.partial functools.partial 通過包裝手法,允許我們 "重新定義" 函數(shù)...
    笨手笨腳越閱讀 2,216評論 1 2
  • functool.reduce 方法是迭代的應(yīng)用傳入的方法用前面得到的值來作為輸入,所以方法最好有兩個以上的變量,...
    茍雨閱讀 880評論 0 1
  • functools模塊用于高級函數(shù):作用于或返回其他函數(shù)的函數(shù),一般來說,任何可調(diào)用對象都可以作為這個模塊的用途來...
    第八共同體閱讀 3,131評論 0 2
  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個常見概念。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,912評論 0 27

友情鏈接更多精彩內(nèi)容