Python-functools (reduce,偏函数partial,lru_cache)
1、functools模塊—reduce()
reduce方法:
reduce方法,就是減少
可迭代對象不能為空,初始值沒提供就在可迭代對象總去一個元素。
def reduce(function, iterable, initializer=None):it = iter(iterable)if initializer is None:value = next(it)else:value = initializerfor element in it:value = function(value, element)return valuereduce()實現代碼舉例1:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' from functools import reduce # reduce() print(reduce(lambda a,x:a + x , range(4))) # 6 print(reduce(lambda a,x:a + x , range(4), 10)) # 16num_l=[1,2,3,100] print(reduce(lambda x,y:x+y,num_l,1)) #可以定義起始值,否則默認起始值為第一個元素 print(reduce(lambda x,y:x+y,num_l)) print(reduce(lambda a,x:a + x , [])) # 報錯,根據定義看,如果沒有初始值,那會去迭代對象取第一個值,但是為空,無法next(it)2、functools ----partial 方法
偏函數:把函數部分的參數固定下來,相當于為部分的參數添加了一個固定的默認值,形成一個新的函數并返回
從 partial 生成的新函數,是對原函數的封裝—裝飾器
def partial(func, *args, **keywords):def newfunc(*fargs, **fkeywords):newkeywords = keywords.copy()newkeywords.update(fkeywords)return func(*args, *fargs, **newkeywords)newfunc.func = funcnewfunc.args = argsnewfunc.keywords = keywordsreturn newfunc舉例 1:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def partial(func, *args, **keywords):def newfunc(*fargs, **fkeywords):newkeywords = keywords.copy()newkeywords.update(fkeywords)return func(*args, *fargs, **newkeywords)''' 這是什么意思?'''# newfunc.func = func# print(newfunc.func) # <function add at 0x00000000029DCF28># newfunc.args = args# print(newfunc.args) # ()# newfunc.keywords = keywords# print(newfunc.keywords) # {'y': 5}return newfuncdef add(x, y):return x + y newadd = partial(add,y=5) # print(newadd(4))舉例2:
from functools import partial import inspectdef add(x:int, y):return x + ynewadd = partial(add, 4) print(inspect.signature(newadd)) print(newadd(5))# (y) # 9newadd = partial(add, y=5) print(inspect.signature(newadd)) print(newadd(4))# (x, *, y=5) # 因為 y=5 是關鍵字傳參,還是可以被更新,所以還是會出現的 # 9newadd = partial(add, x=4,y=5) print(inspect.signature(newadd)) print(newadd())# (*, x=4, y=5) # 9newadd = partial(add,x=4,y=5) print(inspect.signature(newadd)) print(newadd(x=10,y=12))# (*, x=4, y=5) # 22# newadd = partial(add, x=5) # 報錯,雖然x=5被**kwargs收了,但是 4 傳入后是frags,最終賦給x,而后面有x=5,重復 # print(newadd(4))舉例3:針對 from functools import wraps 的分析
'''偏函數作用:把一些函數從多參---變成單參----這些函數就可以當無參裝飾器''' ''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES):def wraps(wrapped, @wraps(fn) 等價 w=wraps(fn)(w) 而wraps(fn)就是一個新函數 assigned = WRAPPER_ASSIGNMENTS, wraps函數中可以看到,傳入 w,其他的都是固定值,同時返回一個偏函數updated = WRAPPER_UPDATES): 偏函數只有第一個參數沒有定,假設生成一個新函數 new()return partial(update_wrapper, wrapped=wrapped,assigned=assigned, updated=updated) 這個new() 只需傳入 update_wrapper參數即可,當傳入后,update_wrapper只剩wrapped這個參數, w=wraps(fn)(w)這個第二個參數就是wfrom functools import update_wrapper,wrapsdef logger(fn):@wraps(fn) # w=wraps(fn)(w)結構就是一個柯里化的樣式def w(*args, **kwargs):''' this is wrapper function'''print('執行業務功能之前')ret = fn(*args, **kwargs)print('執行業務功能之后')return ret# update_wrapper(w, fn)return w@logger # add = logger(add) ----> add = wrapper def add(x, y):''' this is add function''' # 這個只能放在第一行才能打印!!!!!return x + y3、lru_cache
functools.lru_cache(maxsize=128, typed=False)
Least-recently-used 裝飾器,lru 最近最少使用。cache緩存
如果maxsize 設置為 None,則禁用LRU 功能,并且緩存可以無限制增長,當maxsize是二的冪次時,LRU 功能執行的最好
如果typed設置為True,則不同類型的函數將單獨緩存,例如 f(3) 和 f(3.0)將被視為具有不同結果的不同調用。
舉例 1:
from functools import lru_cache import time@lru_cache() # 帶參的裝飾器 def add(x=[], y=1):x.append(y)return xprint(add()) print(add()) # 第二次執行,是直接找上次的結果,并不會在追加,如果不加緩存,就會繼續追加print(add([0])) # 不可hash,以為@lru_cache 原碼影響。lru_cache 源碼分析:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class _HashedSeq(list):""" This class guarantees that hash() will be called no more than onceper element. This is important because the lru_cache() will hashthe key multiple times on a cache miss."""__slots__ = 'hashvalue'def __init__(self, tup, hash=hash):self[:] = tupself.hashvalue = hash(tup)def __hash__(self):return self.hashvaluedef _make_key(args, kwds, typed,kwd_mark = (object(),),fasttypes = {int, str, frozenset, type(None)},tuple=tuple, type=type, len=len):"""Make a cache key from optionally typed positional and keyword argumentsThe key is constructed in a way that is flat as possible rather thanas a nested structure that would take more memory.If there is only a single argument and its data type is known to cacheits hash value, then that argument is returned without a wrapper. Thissaves space and improves lookup speed."""# All of code below relies on kwds preserving the order input by the user.# Formerly, we sorted() the kwds before looping. The new way is *much*# faster; however, it means that f(x=1, y=2) will now be treated as a# distinct call from f(y=2, x=1) which will be cached separately.key = argsif kwds:key += kwd_markfor item in kwds.items():key += itemif typed:key += tuple(type(v) for v in args)if kwds:key += tuple(type(v) for v in kwds.values())elif len(key) == 1 and type(key[0]) in fasttypes:return key[0]return _HashedSeq(key)def lru_cache(maxsize=128, typed=False):# 從原碼可以看出,args 只能是元組,因為最終返回 _HashedSeq(key),而事實上,class _HashedSeq(list): 是元組繼承而來,def __init__(self, tup, hash=hash): # 而且必須可hash,所以list,set,dict都不能, # 對傳入的參數,位置參數賦值給key,之后會添加一個 object() 形成一個新的 tuple,再將關鍵字參數,形成的字典,以元組形式與之前的 # 的元組相加,形成新的元組,最后加一個type 即元素的類型。 # 如下: # from functools import _make_key # key = _make_key((1,2,3),{'a':1},False) # print(key) # [1, 2, 3, <object object at 0x000000000019E160>, 'a', 1] # # print(hash(key)) # -147545184494388729舉例 2:
from functools import lru_cache import time@lru_cache() def add(x=4, y=5):time.sleep(3)return x + yprint(1,add(4,5)) print(2,add(4)) print(3,add(y=5)) print(4,add(x=4,y=5)) print(5,add(y=5,x=4)) print(6,add(4.0,5)) # 如上,每個都要算 3 秒@lru_cache() def add(x=[], y=5):time.sleep(3)x.append(1)return xprint(add([1])) # TypeError: unhashable type: 'list'總結:lru_cache裝飾器應用
使用前提:
同樣的函數參數一定得到同樣的結果
函數執行時間很長,且要多次執行
本質:函數調用的參數 ==> 返回值
缺點:
不支持緩存過期,key無法過期,shixiao
不支持清除操作
不支持分布式,是一個單機緩存
適用場景:單機上需要空間換時間的地方,可以用緩存來將計算編程快速查詢
總結
以上是生活随笔為你收集整理的Python-functools (reduce,偏函数partial,lru_cache)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python-类型注解(3.5引入)
- 下一篇: Python-各种结构解析以及生成器(列