functools模块(partial,lru_cache装饰器)

partial方法

偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回。从partial生成的新函数,是对原函数的封装。

import functools

def add(x, y) -> int:
    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) -> int
import functools

def add(x, y, *args) -> int:
    print(args)
    return x + y

newadd = functools.partial(add, 1,3,6,5)

print(newadd(7))
print(newadd(7, 10))
print(newadd(9, 10, y=20, x=26)) #
print(newadd())

import inspect
print(inspect.signature(newadd))

结果为:

(6, 5, 7)
4
(6, 5, 7, 10)
4
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-148-942fbd3d1b1e> in <module>
      9 print(newadd(7))
     10 print(newadd(7, 10))
---> 11 print(newadd(9, 10, y=20, x=26)) #
     12 print(newadd())
     13 

TypeError: add() got multiple values for argument ‘y‘

partial函数本质

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords): # 包装函数
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func # 保留原函数
    newfunc.args = args # 保留原函数的位置参数
    newfunc.keywords = keywords # 保留原函数的关键字参数参数
    return newfunc

def add(x,y):
    return x+y

foo = partial(add,4)
foo(5)

结果为:
9

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

Least-recently-used装饰器。lru——最近最少使用。cache缓存。缓冲和缓存是两回事。

如果maxsize设置为None,则禁用LRU功能,并且缓存可以无限制增长。当maxsize是二的幂时,LRU功能执行得最好。

如果typed设置为True,则不同类型的函数参数将单独缓存。例如,f(3)和f(3.0)将被视为具有不同结果的不同调用。

import functools
import time
@functools.lru_cache()
def add(x, y, z=3):
    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))

结果为:
9
9
10
10
10
10
10
10

计算过的值可以很快的得到结果,缓存的机制是什么?

lru_cache装饰器

通过一个字典缓存被装饰函数的调用和返回值,key是什么?分析代码看看。

functools._make_key((4,6),{‘z‘:3},False)

结果为:
[4, 6, <object at 0x844718>, ‘z‘, 3]

functools._make_key((4,6,3),{},False)
结果为:
[4, 6, 3]

functools._make_key(tuple(),{‘z‘:3,‘x‘:4,‘y‘:6},False)
结果为:
[<object at 0x844718>, ‘z‘, 3, ‘x‘, 4, ‘y‘, 6]

functools._make_key(tuple(),{‘z‘:3,‘x‘:4,‘y‘:6}, True)
结果为:
[<object at 0x844718>, ‘z‘, 3, ‘x‘, 4, ‘y‘, 6, int, int, int]

可以用lru_cache装饰器实现对斐波那契数列递归方法的改造

import functools

@functools.lru_cache() # maxsize=None
def fib(n):
    if n < 3:
        return n
    return fib(n-1) + fib(n-2)

print([fib(x) for x in range(35)])

结果为:

[0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465]

lru_cache装饰器应用

使用前提:同样的函数参数一定得到同样的结果,函数执行时间很长,且要多次执行,本质是函数调用的参数=>返回值

缺点:不支持缓存过期,key无法过期、失效,不支持清除操作,不支持分布式,是一个单机的缓存。

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

装饰器应用练习

一、实现一个cache装饰器,实现可过期被清除的功能

简化设计,函数的形参定义不包含可变位置参数、可变关键词参数和keyword-only参数

可以不考虑缓存满了之后的换出问题

二、写一个命令分发器

程序员可以方便的注册函数到某一个命令,用户输入命令时,路由到注册的函数

如果此命令没有对应的注册函数,执行默认函数

用户输入用input(">>")

原文地址:https://www.cnblogs.com/xpc51/p/11710768.html

时间: 2024-10-13 09:16:53

functools模块(partial,lru_cache装饰器)的相关文章

关于functools模块的wraps装饰器用途

测试环境:Python3.6.2 + win10 +  Pycharm2017.3 装饰器之functools模块的wraps的用途: 首先我们先写一个装饰器 # 探索functools模块wraps装饰器的用途 from functools import wraps def trace(func): """ 装饰器 """ # @wraps(func) def callf(*args, **kwargs): """

模块大战及装饰器

装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 简单实例 def wrapper(func): def result(): print 'before' func() print 'after' return result @wrapper def foo(): print 'foo' 复杂实例 *****************************************************原理:多层装饰器

functools.wraps定义函数装饰器

def tracer(func): def wrapper(*args, **kwargs): result = func(*args, **kwargs) print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result)) return result return wrapper @tracer def fibonacci(n): if n in (0,1): return n return (fibonacci(n-1)+fibonacci(n

[转] functools.wraps定义函数装饰器

转自:https://www.cnblogs.com/fcyworld/p/6239951.html 装饰器(decorator)是干嘛的? 对于受到封装的原函数来说,装饰器能够在那个函数执行前或者执行后分别运行一些代码,使得可以再装饰器里面访问并修改原函数的参数以及返回值,以实现约束定义.调试程序.注册函数等目标.装饰器一般返回一个包装器(wrapper),而functools.wraps就是装饰包装器的装饰器. 先来看一个不使用functools.wraps的装饰器例子: def trace

Django内置auth模块中login_required装饰器用于类视图的优雅方式

使用多继承 以及类似java中的静态代理模式 原理:OrderView.as_view()根据广度优先,调用的是LoginRequiredMixin中的as_view(cls, *args, **kwargs) 这时的cls=OrderView 接下来super(LoginRequiredMixin, cls).as_view(*args, **kwargs) 会调用到View类中的as_view()并返回一个视图函数 然后,用将这个视图函数作为参数传给Login_required()并返回经过

django的权限认证:登录和退出。auth模块和@login_required装饰器

在settings.py中配置LOGIN_URL参数: # 用户访问带有(@login_required)标签的页面(view)时,如果没有登录,就会跳转到LOGIN_URL(即登陆url). LOGIN_URL = '/login/' 使用django自带的auth模块进行登录和退出: from django.contrib.auth.models import User from django.contrib import auth from django.http.response imp

装饰器,functools,参数注解

装饰器(无参)? 它是一个函数? 函数作为它的形参? 返回值也是一个函数装饰器和高阶函数? 装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)带参装饰器? 它是一个函数? 函数作为它的形参? 返回值是一个不带参的装饰器函数? 使用@functionname(参数列表)方式调用? 可以看做在装饰器外层又加了一层函数函数注解? Python 3.5引入? 对函数的参数进行类型注解? 对函数的返回值进行类型注解? 只对函数参数做一个辅助的说明,并不对函数参数进行类型检查? 提供给第三方工具

Python 中实现装饰器时使用 @functools.wraps 的理由

Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下--比如测试时--会导致一些问题.Python 通过 functool.wraps 为我们解决了这个问题:在编写装饰器时,在实现前加入 @functools.wraps(func) 可以保证装饰器不会对被装饰函数造成影响.比如,在 Flask 中,我们要自己重写 login_required 装饰器,但不想影响被装饰器装饰的方法,则 login_req

python functools模块

functools.partial 作用: functools.partial 通过包装手法,允许我们 "重新定义" 函数签名 用一些默认参数包装一个可调用对象,返回结果是可调用对象,并且可以像原始对象一样对待 冻结部分函数位置函数或关键字参数,简化函数,更少更灵活的函数参数调用 #args/keywords 调用partial时参数 def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newk