Python的functools模块

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无法过期,失效。不支持清除操作,不支持分布式,是一个单机的缓存。

使用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询。

posted @ 2018-11-12 17:00  Python爱好者666  阅读(872)  评论(0)    收藏  举报