介绍

functools模块提供了一些工具来管理或扩展和其他callable对象,从而不必完全重写

修饰符

偏函数partial

from functools import partial

'''
functools模块提供的主要工具就是partial类,可以用来包装一个有默认参数的callable对象。
得到的对象本身就是callable,可以把它看作是原来的参数。
''' # 举个栗子
def foo(name, age, gender):
print(name, age, gender) p = partial(foo, "mashiro", 16)
p("female") # mashiro 16 female
'''
可以看到p相当于是已经绑定了name和age的foo函数,name我们在传参的时候只需要传入一个gender就可以了
这个函数的源码实现比较复杂,但是如果以简单的装饰器的方式实现就很清晰了
''' def my_partial(f, name, age):
def inner(gender):
return f(name, age, gender)
return inner p = my_partial(foo, "satori", 16)
p("female") # satori 16 female
'''
可以看到,当我调用my_partial(foo, "satori", 16)的时候,返回了inner函数
此时的p相当于是inner,当我再调用p("female")的时候,等价于调用inner("female")
然后将两次传入的参数,按照顺序组合起来传递给foo函数,如果不限制参数的话就是:
def my_partial(f, *args1, **kwargs1):
def inner(*args2, **kwargs2):
from collections import ChainMap
args = args1 + args2
kwargs = dict(ChainMap(kwargs1, kwargs2))
return f(*args, **kwargs)
return inner 所以一定要和原函数的参数顺序保持一致,如果我传入p = my_partial("mashiro", 16),此时"mashiro"会传给name,16传给age
我再调用p(name="xxx")的话,肯定会报错的,参数重复指定了
因此务必注意参数的传递顺序。 个人觉得这个偏函数最大的作用就是解决了回调函数只能传入函数名、但却又想传参时候的尴尬。
'''

可以把partial看成是一个简单的装饰器,装饰器不仅可以装饰函数,还可以装饰类,只要是callable对象,说白了只要是能加上()的都可以。这就是Python的魅力,非常的动态。比如列表进行extend, 其实不仅仅可以extend一个列表,还可以是元组,甚至是字典,只要是iterable对象都可以。

from functools import partial

class A:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender def print_info(self):
print(f"name: {self.name}, age: {self.age}, gender: {self.gender}") p = partial(A, "mashiro", 16)
a = p("female") # 这两步等价于 a = A("mashiro", 16, "female")
a.print_info() # name: mashiro, age: 16, gender: female
from functools import partial
import functools '''
默认情况下,partial对象没有__name__属性的,如果没有这些属性,那么被修饰的函数会很难调试。
''' def foo():
pass print(foo.__name__) # foo
p = partial(foo)
try:
print(p.__name__)
except AttributeError as e:
print(e) # 'functools.partial' object has no attribute '__name__' # 那么如何添加呢?首先增加到包装器的属性在WRAPPER_ASSIGNMENTS中定义,另外WRAPPER_UPDATES列出了要修改的值
print("assign:", functools.WRAPPER_ASSIGNMENTS) # assign: ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')
print("update:", functools.WRAPPER_UPDATES) # update: ('__dict__',) # 添加,表示从原函数将属性赋值或增加到partial对象
functools.update_wrapper(p, foo)
print(p.__name__) # foo

partialmethod

partial返回一个可以直接使用的callable,partialmethod返回的callable则可以用做对象的非绑定方法

from functools import partial, partialmethod

def standalone(self):
print(f"self = {self}") class A:
method1 = partial(standalone)
method2 = partialmethod(standalone) a = A()
try:
a.method1()
except TypeError as e:
# 由于standalone需要一个参数self,我们这里没有传,因此报错
print(e) # standalone() missing 1 required positional argument: 'self' # 但是我们调用method2呢?
a.method2() # self = <__main__.A object at 0x0000000002964588>
'''
得到了一个A的实例对象。
所以,partial在哪里调用时没有区别的,必须手动显示地传递,该是几个就是几个。
但是在类中如果使用partialmethod定义的话,那么在使用实例调用的话,会自动将实例作为第一个参数传进去。
'''

wraps

from functools import wraps

'''
我们在知道在使用装饰器装饰完函数的时候,属性会变。比如:
''' def deco(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner @deco
def foo():
pass # 函数从下到下执行,加上@deco等价于,foo = deco(foo) = inner,也就是说此时的foo不再是foo了,已经是inner了
print(foo.__name__) # inner
# 那么如何在装饰的时候,还保证原来函数的信息呢 def deco(func):
@wraps(func) # 只需要加上这一个装饰器即可,会自动对所修饰的函数应用update_wrapper
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner @deco
def bar():
pass # 可以看到原来函数的信息并没有改变,不仅仅是函数名,还包括__doc__等其他元信息
print(bar.__name__) # bar

比较

import functools

'''
在Python2中,类可以有一个__cmp__()方法,它会根据这个对象小于、等于、或者大于所比较的元素而分别返回-1、0、1.
Python2.1中引入了富比较(rich comparision)的方法。
如:__lt__(),__gt__(),__le__(),__eq__(),__ne__(),__gt__()和__ge__(),可以完成一个比较操作并返回一个bool值。
Python3已经废弃了__cmp__()方法。
另外,functools提供了一些工具,从而能更容易地编写符合新要求的类,即符合Python3中新的比较需求。
''' @functools.total_ordering
class A:
def __init__(self, val):
self.val = val def __eq__(self, other):
return self.val == other.val def __gt__(self, other):
return self.val > other.val a1 = A(1)
a2 = A(2)
print(a1 < a2) # True '''
这个类必须提供__eq__()和另外一个富比较方法的实现,这个修饰符会自动增加其余的方法。
'''

另外还可以用于sort函数中,不过更推荐使用lambda函数,因此了解就好

import functools

'''
由于Python3废弃了老式的比较函数,sort()之类的函数中也不再支持cmp参数。
对于使用了比较函数的较老的程序,可以使用cmp_to_key()将比较函数转换为一个比对键的函数,这个键用于确定元素在最终序列中的位置
''' def compare_obj(a, b):
if a < b:
return -1
elif a > b:
return 1
else:
return 0 l = [1, 5, 2, 11, 2, 44, 54, 5, 1] print(sorted(l, key=functools.cmp_to_key(compare_obj))) # [1, 1, 2, 2, 5, 5, 11, 44, 54]

缓存

import functools

'''
lru_cache()修饰符将一个函数包装在一个"最近最少使用的"缓存中。函数的参数用来建立一个散列键,然后映射到这个结果。
后续调用如果有相同的参数,就会从这个缓存中获取值而不会再次调用这个函数。
这个修饰符还会为函数增加方法来检查缓存的状态(cache_info)和清空缓存(cache_clear)
''' @functools.lru_cache() # 里面可以执行参数maxsize,默认是128
def foo(a, b):
print(f"foo({a} * {b})")
return a * b print("第一次调用")
for i in range(2):
for j in range(2):
foo(i, j)
print(foo.cache_info())
"""
第一次调用
foo(0 * 0)
foo(0 * 1)
foo(1 * 0)
foo(1 * 1)
CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)
""" print("\n第二次调用")
for i in range(3):
for j in range(3):
foo(i, j)
print(foo.cache_info())
"""
第二次调用
foo(0 * 2)
foo(1 * 2)
foo(2 * 0)
foo(2 * 1)
foo(2 * 2)
CacheInfo(hits=4, misses=9, maxsize=128, currsize=9)
""" print("清除缓存") # 清除缓存
foo.cache_clear()
print(foo.cache_info()) # CacheInfo(hits=0, misses=0, maxsize=128, currsize=0) print("\n第三次调用")
for i in range(2):
for j in range(2):
foo(i, j)
print(foo.cache_info())
"""
第三次调用
foo(0 * 0)
foo(0 * 1)
foo(1 * 0)
foo(1 * 1)
CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)
"""
# 我们观察一下第二次调用,3 * 3应该是9次,为什么只有5次,因为第一次调用有4次执行过了,放到缓存里,因此不需要执行了

reduce

import functools

'''
reduce这个函数无需介绍,在Python2中是内置的,但是在Python3中被移到functools下面
'''
l = range(100)
print(functools.reduce(lambda x, y: x+y, l)) # 4950
print(functools.reduce(lambda x, y: x+y, l, 10)) # 4960
print(functools.reduce(lambda x, y: x+y, l, 100)) # 5050 l = [1, 2, 3, 4, 5]
print(functools.reduce(lambda x, y: x*y, l)) # 120

泛型函数

import functools

'''
在类似Python的动态类型语言中,通常需要基于参数的类型完成稍有不同的操作,特别是在处理元素列表与单个元素的差别时。
直接检查参数的类型固然很简单,但是有些情况下,行为差异可能被隔离到单个的函数中。
对于这些情况,functools提供了singledispatch修饰符来注册一组泛型函数,可以根据函数第一个参数的类型自动切换
''' @functools.singledispatch
def myfunc(arg):
print(f"default myfunc {arg}") @myfunc.register(int)
def myfunc1(arg):
print(f"myfunc1 {arg}") @myfunc.register(list)
def myfunc2(arg):
print(f"myfunc2 {arg}") myfunc("string") # default myfunc string
myfunc(123) # myfunc1 123
myfunc(["1", "2"]) # myfunc2 ['1', '2']
'''
可以看到使用signledispatch包装的是默认实现,在未指定其他类型特定函数的时候就用这个默认实现。
myfunc,myfunc1,myfunc2都可以调用,但是我们一般只调用被singledispatch装饰的myfunc
其它函数则是通过myfunc.register(类型)进行注册,然后执行myfunc,根据参数类型的不同,执行不同的函数。
比如我们注册了int、list,传入类型为int,执行myfunc1,传入list执行myfunc2。如果是没有注册的类型,那么走默认的myfunc
'''

functools:管理函数的工具的更多相关文章

  1. Python3标准库:functools管理函数的工具

    1. functools管理函数的工具 functools模块提供了一些工具来调整或扩展函数和其他callable对象,从而不必完全重写. 1.1 修饰符 functools模块提供的主要工具就是pa ...

  2. functools:管理函数工具(部分)

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #functools:管理函数工具 #作用:处理其他函数的函数 #版 ...

  3. webpack模块化管理和打包工具

    Webpack简介 webpack是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.还可以将按需加载的模块进行代码分隔,等到实际 需要的 ...

  4. 函数计算工具链新成员 —— Fun Local 发布啦

    刚刚,我们发布了函数计算工具链的新成员,Fun Local.欢迎大家使用! 如果你还不了解 Fun 是什么,我们来简单解释下. Fun 是什么 Fun 是 have Fun with Serverle ...

  5. Webapi管理和性能测试工具WebBenchmark

    WebBenchmark是一款基于开源通讯组件Beetlex扩展的Webapi管理和性能测试工具,在传统工具中一般管理工具缺乏性能压测能力或有性能测试的缺少管理功能:WebBenchmark的设计目标 ...

  6. java面试复习重点:类的管理及常用工具,教你抓住面试的重点!

    java复习: 类的管理及常用工具类 包 写在程序文件的第一行 一个Java 源文件中只能声明一个包, 且声明语句只能作为源文件的第一条指令 导入类能导入非public类,但是不能用因为在其他包缺省的 ...

  7. Webpack:前端资源模块化管理和打包工具

    一.介绍: Webpack 是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生 产环境部署的前端资源.还可以将按需加载的模块进行代码分隔,等到实际需要的时候再 ...

  8. μC/OS-Ⅲ系统的时间管理函数和定时器

    一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方 ...

  9. Unity协程(Coroutine)管理类——TaskManager工具分享

    博客分类: Unity3D插件学习,工具分享 源码分析   Unity协程(Coroutine)管理类——TaskManager工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处 ...

随机推荐

  1. Dubbo架构与底层实现

    一.Dubbo的设计角色 (1)系统角色Provider: 暴露服务的服务提供方.Consumer: 调用远程服务的服务消费方.Registry: 服务注册与发现的注册中心.1Monitor: 统计服 ...

  2. Python 面向对象--继承,实现,依赖,关联,聚合,组合

    一. 继承 继承指的是子类继承父类除私有内容以外的其他所有内容, 并且子类具有增加自己新内容的能力. 举例说明: class Animal: print("吃是动物的本能") cl ...

  3. 【CodeForces - 707B】Bakery(思维水题)

    Bakery Descriptions 玛莎想在从1到n的n个城市中开一家自己的面包店,在其中一个城市烘焙松饼. 为了在她的面包房烘焙松饼,玛莎需要从一些储存的地方建立面粉供应.只有k个仓库,位于不同 ...

  4. 【CodeForces - 598D】Igor In the Museum(bfs)

    Igor In the Museum Descriptions 给你一个n*m的方格图表示一个博物馆的分布图.每个方格上用'*'表示墙,用'.'表示空位.每一个空格和相邻的墙之间都有一幅画.(相邻指的 ...

  5. DP经典问题—————(LCIS)最长公共上升子序列

    这道题是LIS(最长上升子序列)与LCS(最长公共子序列)问题的综合版本,有关这两个问题可以看一下我的文章:https://www.cnblogs.com/myhnb/p/11305551.html ...

  6. linux系统下安装python3及其配置

    Linux下安装Python3.6和第三方库 linux一般自带python2,不要动它,使用python3运行python脚本就好,部分linux系统命令依赖目前的python2环境, 比如yum! ...

  7. [转帖]Nginx 容器教程

    Nginx 容器教程 http://www.ruanyifeng.com/blog/2018/02/nginx-docker.html 里面有证书. 作者: 阮一峰 日期: 2018年2月27日 感谢 ...

  8. gRPC 本地服务搭建

    RPC RPC 原理 主流 RPC 框架 gRPC 概述 特点 服务端创建 定义服务 生成 gRPC 代码 服务端实现 客户端实现 踩坑记录 源码 RPC RPC 原理 RPC 框架的目标就是让远程服 ...

  9. 【LOJ】#3119. 「CTS2019 | CTSC2019」随机立方体

    题解 用容斥,算至少K个极大值的方案数 我们先钦定每一维的K个数出来,然后再算上排列顺序是 \(w_{k} = \binom{n}{k}\binom{m}{k}\binom{l}{k}(k!)^3\) ...

  10. Symfony4框架中单元测试和接口测试中的一些小坑

    前提说明: symfony 版本 4.1.*,使用  composer create-project symfony/website-skeleton  进行安装. 目标:在一个单元测试用例中对当前工 ...