介绍

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. matlab中如何给一个矩阵中的某几个特定位置赋值

    用sub2ind >> a=zeros(5); i = [2;3;4]; j = [1;4;2]; >> a(sub2ind(size(a), i, j))=1 a = 0 0 ...

  2. zabbix3.0升级到4.0

    升级步鄹: 3.0->3.2 1.停服务 service zabbix-server stop 2.备份配置文件 #cp /etc/zabbix/zabbix_server.conf /data ...

  3. ARB扩展与标准OpenGL的关系

    由于OpenGL的标准更新不是很频繁,因此,当某种技术应用流行起来时,显卡厂商为了支持该技术,会使用自己的扩展来实现该功能.但是不同厂商如果有不同的实现,那么程序编写将会异常繁琐.因此多个厂商共同协商 ...

  4. ubuntu14+ns2

    https://www.linuxidc.com/Linux/2017-03/141504.htm 环境变量改为: export PATH=$PATH:/home/zgh/Desktop/ns-all ...

  5. 【并行计算-CUDA开发】CUDA存储器模型

    CUDA存储器模型 除了执行模型以外,CUDA也规定了存储器模型(如图2所示)和一系列用于主控CPU与GPU间通信的不同地址空间.图中红色的区域表示GPU片内的高速存储器,橙色区域表示DRAM中的的地 ...

  6. Plsql配置后,sql语句可以简写 快速使用

    in=INSERT up=UPDATE se=SELECT fr=FROM wh=WHERE or=ORDER BY de=DELETE df=DELETE FROM sf=SELECT * FROM ...

  7. spring boot 使用elasticsearch

    在文章开始之前我们先来介绍一下elasticsearch 是一个分布式的 RESTful 风格的搜索和数据分析引擎. 查询 : Elasticsearch 允许执行和合并多种类型的搜索 — 结构化.非 ...

  8. 小a的强迫症 题解

    题面: 小a是一名强迫症患者,现在他要给一群带颜色的珠子排成一列,现在有N种颜色,其中第i种颜色的柱子有num(i)个.要求排列中第i种颜色珠子的最后一个珠子,一定要排在第i+1种颜色的最后一个珠子之 ...

  9. python-open函数

    open函数,该函数用于文件处理 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = open('文件路径', '模式') 打开文件时,需要指定文件路径和以何等方式 ...

  10. 牛客 70E 乌龟跑步 (bitset优化dp)

    有一只乌龟,初始在0的位置向右跑. 这只乌龟会依次接到一串指令,指令T表示向后转,指令F表示向前移动一个单位.乌龟不能忽视任何指令.现在我们要修改其中正好n个指令(一个指令可以被改多次,一次修改定义为 ...