1)Partial方法
2)偏函数,把函数部分的参数固定下来,相当于为部分参数添加了一个固定的默认值,形成一个新的函数返回。
3) 一定返回的是新的函数,原来的函数包在内了。
(1)例题
from functools import partial
def add(x,y):
return x +y
newadd = partial(add,4)
print(newadd(5))
例题,把x固定了。
from functools import partial
import inspect
def add(x,y):
return x +y
newadd = partial(add,x=4)
print(newadd(y=5))
print(inspect.signature(newadd))
#打印出的:
9
( *,x=4, y)
根据签名得到,被固定的参数的前面增加,*,
#课堂例子:
import functools
def add(x,y):
return x+y
newadd = functools.partial(add,y=5)
print(newadd(7))
print(newadd(7,y=6))
print(newadd(y=10,x=6))
import inspect
print(inspect.signature((newadd)))
#12
13
16
(x, *, y=5)
被固定的是add的函数的y的值,所以签名是(x,*,y=5),所以传参的方式x使用位置或者关键字均可以,y可以使用关键字传参,不传参的话可以使用默认值。
(2)例题:
import functools
def add(x,y,*args):
print(args)
return x+y
newadd = functools.partial(add,1,3,5,6)
print(newadd(7))
print(newadd(7,10))
print(newadd(9,10,x=2,y=4)) # 一定不可以,因为x,y被固定了,被填充满了,在添加值是不可以的。
print(newadd())
import inspect
print(inspect.signature(newadd))
4) partial函数的本质。(本质就是元组和字典合并。)
def partial(func,*args,**kwargs):
def newfunc(*fargs,**fkwargs):#包装函数
newkwargs = kwargs.copy() #关键字参数拷贝 (调用时候才会执行)
newkwargs.update(fkargs) #关键词传参参数全部更新,(调用时候才会执行)
return func(*(args+fargs),**newkwargs) #元素依次的合并,返回一个新的元组,不去重的。(调用时候才会执行)
newfunc.func = func #保留原来的函数
newfunc.args = args #保留原函数的位置参数 空元组
newfunc.kwargs = kwargs #保留原函数的关键字参数。 #字典。
return newfunc #返回一个新的函数
def add(x,y):
return x+y
foo = partial(add,4)
foo(5)
5)functools.lru_cache(maxsize=128,typed=False)
lru 最近最少使用,cache缓存。
如果maxsize设置的是none,所以禁用了LRU功能,并且缓存可以无限制的增长,当maxsize是2的次幂的时候,LRU执行良好。
如果typed设置为True,则不同类型的函数参数将单独缓存,例如;f(3)和f(3.0)视为不同结果的不同调用。
import functools
@functools.lru_chache()
def add(x,y,z=5):
time.sleep(z)
return x+y
print(add(4,5))
print(add(4.0,5))
print(add(4,6))
print(add(4,6,3))
print(add(6,4))
print(add(4,y=6))
print(add(x=4,y=6))
print(add(y=6,x=4))
总结:第一个print和第二个一样。
第七个和第八个一样。其余的不一样。
缓存机制是什么:利用字典,结果放在value中,k为add的参数。
lru_cache装饰器。
通过一个字典缓存被装饰函数的调用和返回值。
#第一个类型
import functools
functools._make_key((4,6),{'z':3},False)
#打印[4, 6, <object at 0x7f98aa654090>, 'z', 3]
返回的是一个列表。前面的元素是args。。后面是kwargs。<object at 0x7f98aa654090>代表的是符号。
#第二个类型
import functools
functools._make_key((4,6,3),{},False)
生成的是列表。
#打印出[4, 6, 3]
#第三个类型
functools._make_key(tuple(),{'z':3,'x':4,'y':6},False)
#打印出[<object at 0x7f98aa654090>, 'x', 4, 'y', 6, 'z', 3]进行了排序。
#第四个类型
functools._make_key(tuple(),{'z':3,'x':4,'y':6},True)
#打印出[<object at 0x7f98aa654090>, 'x', 4, 'y', 6, 'z', 3, int, int, int]
总结:pyted改为True显示类型。缺省值就是false。
Object把二元组里面的元素加进去。
_make_key..
顺序,拆开k显示的是不同的。
@functools.lru_cache()改造斐波那契数列。
import functools
@functools .lru_cache(maxsize=100)
def fib(n):
if n<3:
return 1
else:
return fib(n-1)+fib(n-2)
n=fib(5)
print(n)
import functools
@functools .lru_cache(maxsize=100)
def fib(n):
if n<3:
return 1
else:
return fib(n-1)+fib(n-2)
print([fib(x) for x in range(35)])
原因利用缓存:因为计算的结果下一项利用到了上一项。倒向运算。所有的计算所需的数据都来自缓存,无须再次计算啦。
6)总结:
使用前提,同样的函数参数一定得到同样的结果。
函数执行时间长,且要执行很多次。
本质上是函数调用函数 =》返回值。
缓存的缺点,不支持缓存过期,key无法过期,失效。不支持清除操作,不支持分布式,是一个单机的缓存。
使用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询。