龙空技术网

Python 模块 Functools

许良alex 244

前言:

而今大家对“pythonfunctools”可能比较注意,朋友们都想要了解一些“pythonfunctools”的相关文章。那么小编同时在网络上收集了一些对于“pythonfunctools””的相关文章,希望看官们能喜欢,大家快快来学习一下吧!

模块 functools 是处理函数的工具库。不仅可以适配(adapting)和扩展(extending)可调用的对象(callable object),还可以重写(rewriting)他们。

partial

模块 functools 的一个很重要的函数就是 partial(),它可以包装(wrap)一个可调用的对象,并传递一些默认的参数。返回的结果仍然是可调用的对象,你可以认为它和原来的函数一样,只是传递了一些默认的参数。调用时可以传递参数或者命名参数

执行:

本例中,使用 partial() 函数包装了函数 f1,生成了2个新的可调用的函数 p1()和 p2()。p1() 提供了默认值 b=3,p2() 提供了默认值 a=3。partial() 函数也叫偏函数。

调用返回的函数时,还也可以通过命名参数覆盖默认值。需要注意的是,参数如果没有默认值,调用的时候必须要传入参数值。

例如,p1() 和 被包装的函数 f1(),a 都没有默认值, 如果不传参数,直接调用 p1(),则抛出异常。

其他可调用的对象

partial() 不仅能用在函数上,也可用于其他可调用的对象。例如实现了 __call__() 方法的自定义类

执行:

本例中,类 A 实现了 __call__() 方法,所以它的实例是可调用的,用 partial() 函数包装了实例对象 a,然后提供了2个默认值。返回的对象 p 也是可调用的。

方法和函数(Methods and Functions)

partial() 包装返回的对象是直接可调用的,partialmethod() 返回的也是可调用的,可以作为另一个对象的未绑定的方法(unbound method)。

执行:

这个例子中,首先定义了一个独立(standalone)的函数 f1,接收三个参数。在类 A中,分别使用 partialmethod 和 partial 包装独立函数 f1。

从输出可以看到,实例对象可以直接调用使用 partialmethod 生成的方法 m1 ,实例对象自动传入 f1 的第一个参数 self。

方法 m2 不是一个绑定方法(bound method),所以不能直接调用。self 必须显示的传入,否则触发错误 TypeError。调用的时候传入第一个参数 a.m2(a) 就不会报错。

获取装饰器内函数的属性

更新装饰器返回的函数属性是很有用的,因为返回的函数没有原始函数的信息(名称和文档字符串)。这样更方便调试程序,知道实际调用的是哪个函数。

执行:

例子中,定义了函数 show_details() 打印传入函数的信息,函数名称、属性 __name__ 和 __doc__。

当传入一个未包装的函数 f2 时,正确打印出了 f2 的信息,但是当打印一个包装函数 wrap_func 时,返回的信息是 f1 内部函数 h 的信息。这样当调试的时候,不知道访问的真实函数是什么。

现在取消内部函数 h 上的装饰器 @functools.wraps(f) 注释,然后再打印输出:

@functools.wraps 可以把原始函数的信息(名称和文档字符串)更新到返回的函数上面。

update_wrapper

partial 对象没有原始函数的 __name__ 和 __doc__ 信息,调用 partial 对象或者调试的时候,会不知道调用的真实函数是谁,使用 update_wrapper() 函数可以将原始函数的信息复制或添加到 partial 对象上。

执行:

使用 functools.update_wrapper(p1, f1) 把 f1 的 __name__ 和 __doc__都复制到了 partial 对象 p1 上面。

比较

在 Python 2中,类会定义 __cmp__ 方法返回 -1, 0, 1 来确定对象是否小于,等于,大于另一个对象。Python 2.1 中引入了6个比较方法(小于 __lt__、 小于等于 __le__、 等于 __eq__、 不等于__ne__、 大于__gt__、 大于等于__ge__)返回 Boolean 类型确定结果。

Python 3 废弃(deprecated)了 __cmp__ 方法。

functools 模块提供了 total_ordering() 方法,实现对象的比较时,你可以不必都实现上述的6个方法,只需要提供少数几个方法,剩余的会自动实现。

执行:

类 A 只提供了 __eq__ 和 __gt__ 两个比较方法,剩余的方法由装饰器自动实现。查看输出,两个对象的5次比较都返回了正确的值。

cmp_to_key

因为旧的比较函数已经在 Python 3 中废弃了,函数 sort() 就不再支持 cmp 参数。旧的比较函数可以使用 cmp_to_key() 方法把自身转变为 Python 3 中可以用于排序的 key,它确定元素在序列最终的位置。

执行:

本例中,把旧的比较函数 cmp_old() ,使用方法 cmp_to_key() 转为排序时用的 key 参数。最后打印了排好序的对象列表。

cmp_to_key() 函数的返回值是 functools 模块里的类的一个实例,它已经实现了 Python 3 中新的比较接口(上述的6个比较方法)。

缓存 lru_cache

使用 lru_cache() 装饰器装饰一个函数,这个函数就可以把对应的参数和结果作为映射缓存起来。算法使用的是最近最少使用缓存(least-recently-cache)。参数必须是可哈希的(hashable),因为它会用来做为映射的键。在后面的调用中,如果参数在之前使用过,就从缓存获取。

装饰器添加了获取缓存信息(cache_info)和清空缓存(cache_clear)的函数。

执行:

本例中,当运行第一个嵌套循环的时候,进行了4次乘法,查看缓存的信息,命中缓存数 hits 是0,未命中缓存 misses 就是4次,缓存当前大小 currsize 为4。

第二个嵌套循环,应该是进行9次乘法。查看输出的信息,只有5个 work 输出,有4次命中 hits 了缓存,5次没有命中。加上第一个嵌套循环的4次,一共9次 misses。

可以给 lru_cache() 函数一个参数 maxsize ,最大缓存数量。可以防止长时间运行的程序占用过多的空间。

因为函数的参数必须是可哈希的(hashable),如果传入的类型是可变的,例如列表,字典就会抛出异常TypeError 类型错误。

执行:

reduce

reduce() 函数接收一个可调用的(callable)对象和一个序列,然后生成单个的值返回。序列的值依次传入可调用的对象 callable ,每次调用的结果累积起来最后返回。

执行:

本例中,计算1到6数字之和,最后返回了正确结果为21。6个数字调用了函数 worker 5次。查看输出可推测出计算过程。首先前两个数1和2调用函数,得出结果3,3再和第三个数字3相加得出6,以此类推,返回6个数字之和。

reduce() 还有可选的(optional)的第三个参数,初始值 initiallizer,若提供了此值,它也会参加计算。

执行:

如果序列中值包含一个元素,没有初始值 initializer 时,就返回那个元素。有初始值,则初始值和那一个元素应用调用对象 callable,然后返回结果。

如果为空序列,又没有提供默认值,则抛出异常 TypeError 类型错误。有默认值则返回默认值。

singledispatch

使用 singledispatch 装饰器装饰一个函数,会根据参数类型判断调用哪个方法。

singledispatch 相当于注册了一个泛型函数(generic functions)。

执行:

标签: #pythonfunctools