py3.7标准库-functools

本文介绍了 Python 3.7 标准库 `functools` 中的关键功能,包括 `cmp_to_key`、`lru_cache` 缓存技术、`total_ordering` 自动比较方法、`partial` 和 `partialmethod` 用于函数部分应用、`reduce` 用于序列累加、`singledispatch` 实现泛函数以及 `update_wrapper` 和 `wraps` 用于修饰器功能。通过实例演示了这些功能的用法和效果,展示了它们在提高代码效率和可读性上的作用。
摘要由CSDN通过智能技术生成

参考文档:

functools.cmp_to_key(func)

将旧式比较函数转换为关键字函数。与接受字关键函数(如sort()、min()、max()、heapq. nbiggest()、heapq.nsmallest()、itertools.groupby())的工具一起使用。该函数主要用于从Python 2转换过来的程序的转换工具,Python 2支持使用比较函数。

比较函数是任何可调用的函数,它接受两个参数,进行比较,然后返回负数(小于)、零(相等)或正数(大于)。键函数是一个可调用函数,它接受一个参数并返回另一个值作为排序键。

放上一波源码:

################################################################################
### cmp_to_key() function converter
################################################################################

def cmp_to_key(mycmp):
    """Convert a cmp= function into a key= function"""
    class K(object):
        __slots__ = ['obj']
        def __init__(self, obj):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        __hash__ = None
    return K

写一个demo,看一下运行流程:

import functools


class MyObject:

    def __init__(self, val):
        self.val = val

    def __str__(self):
        return 'MyObject({})'.format(self.val)


def compare_obj(a, b):
    """Old-style comparison function.
    """
    print('comparing {} and {}'.format(a, b))
    if a.val < b.val:
        return -1
    elif a.val > b.val:
        return 1
    return 0

# 排序的key
get_key = functools.cmp_to_key(compare_obj)

def get_key_wrapper(o):
    "Wrapper function for get_key to allow for print statements."
    new_key = get_key(o)
    print('key_wrapper({}) -> {!r}'.format(o, new_key))
    return new_key

objs = [MyObject(x) for x in range(5, 0, -1)]

for o in sorted(objs, key=get_key_wrapper):
    print(o)

通常情况下,cmp_to_key() 将直接使用,但在本例中引入了一个额外的包装函数,以在调用关键函数时输出更多信息。
输出如下:

key_wrapper(MyObject(5)) -> <functools.KeyWrapper object at 0x10692e510>
key_wrapper(MyObject(4)) -> <functools.KeyWrapper object at 0x10692e4f0>
key_wrapper(MyObject(3)) -> <functools.KeyWrapper object at 0x10692e4d0>
key_wrapper(MyObject(2)) -> <functools.KeyWrapper object at 0x10692e470>
key_wrapper(MyObject(1)) -> <functools.KeyWrapper object at 0x10692e490>
comparing MyObject(4) and MyObject(5)
comparing MyObject(3) and MyObject(4)
comparing MyObject(2) and MyObject(3)
comparing MyObject(1) and MyObject(2)
MyObject(1)
MyObject(2)
MyObject(3)
MyObject(4)
MyObject(5)

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

这个装饰器实现了备忘的功能,是一项优化技术,把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。lru 是(least recently used)的缩写,即最近最少使用原则。表明缓存不会无限制增长,一段时间不用的缓存条目会被扔掉。
这个装饰器支持传入参数,还能有这种操作的?maxsize 是保存最近多少个调用的结果,最好设置为 2 的倍数,默认为 128。如果设置为 None 的话就相当于是 maxsize 为正无穷了。还有一个参数是 type,如果 type 设置为 true,即把不同参数类型得到的结果分开保存,如 f(3) 和 f(3.0) 会被区分开。

由于字典用于缓存结果,因此函数的位置和关键字参数必须是hashable的。

如果maxsize设置为None,则禁用LRU特性,缓存可以无限制增长。当maxsize为2次方时,LRU特性表现最佳。

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

为了帮助度量缓存的有效性并调优maxsize参数,封装的函数使用cache_info()函数进行检测,该函数返回一个命名元组,显示hits(命中), misses(未命中)、maxsize和currsize。在多线程环境中,得失是近似的。

decorator还提供了一个cache_clear()函数,用于清除或使缓存失效。

原始的底层函数可以通过wrapped属性访问。这对于内省、绕过缓存或使用不同的缓存重新包装函数非常有用。

写了个函数追踪结果

def track(func):
    @functools.wraps(func)
    def inner(*args):
        result = func(*args)
        print("{} --> ({}) --> {} ".format(func.__name__, args[0], result))
        return result
    return inner

递归函数适合使用这个装饰器,那就拿经典的斐波那契数列来测试吧

不使用缓存

@track
def fib(n):
    if n < 2:
        return n
    return fib(n - 2) + fib(n - 1)

使用缓存

@functools.lru_cache()
@track
def fib_with_cache(n):
    if n < 2:
        return n
    return fib_with_cache(n - 2) + fib_with_cache(n - 1)

测试代码

fib(10)

fib
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值