functools模块提供了某些高阶函数(high-order function)。

functools.cmp_to_key(func)

比较函数是接收两个参数进行比较的函数,返回一个负数表示。key函数接收一个参数并返回另一个值作为进行排序的键。

将比较函数转换为key函数,常在用到key关键字的函数如sotred(), min(), heapq.nlargest(), itertools,groupby()中使用。cmp_to_key主要作为过渡工具将python2中支持的比较函数进行转换。

def numeric_compare(x, y):

return x - y

# python2

print(sorted([5, 2, 4, 1, 3], cmp=numeric_compare))

# python3

print(sorted([5, 2, 4, 1, 3], key=cmp_to_key(numeric_compare)))

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

使用memoize包装函数,保存最近maxsize次的函数调用结果。在I/O-bound函数上装饰,处理相同参数时可以节省函数执行时间。

如果maxsize为None,会禁用LRU缓存特性(并非禁用缓存)且缓存大小会无限增长。maxsize设置为2的n次方时性能最优。

如果typed为True,不同类型函数参数的执行结果会被分别缓存,例如f(3)和f(3.0)会被视为有两个不同结果的不同调用。

因为该装饰器使用字典缓存函数执行结果,所以函数的位置参数和关键字参数必须是可哈希的。

不同的参数模式可能会被视为不同的缓存实体。例如f(a=1, b=2)和f(b=2, a=1)虽然只是关键字顺序不同但可能有两个单独的缓存实体。

被包装的函数可以调用cache_info(),它返回一个(hits, misses, maxsize, currsize)形式的命名元组;可以调用cache_clear()清空或使缓存无效;还可以调用__wrapped__属性绕过缓存,访问原始的底层函数。

LRU(least recently used)缓存通常应仅用在需要重用先前计算的值的场景,其他场景如使用LRU有不良影响、每次调用需要返回不同结果、time()、random()等应禁止使用。maxsize表示缓存大小限制,确保不会无限制增长。

@lru_cache(maxsize=32)

def get_pep(num):

'Retrieve text of a Python Enhancement Proposal'

resource = 'http://www.python.org/dev/peps/pep-%04d/' % num

try:

with urllib.request.urlopen(resource) as s:

return s.read()

except urllib.error.HTTPError:

return 'Not Found'

>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:

... pep = get_pep(n)

... print(n, len(pep))

>>> get_pep.cache_info()

CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)

@functools.total_ordering

类装饰器,包装在定义了一个或多个富比较排序方法的类上,会补足其他的比较方法。

该类必须定义__lt__(), __le__(), __gt__(), 或__ge__()中至少一个方法,并建议定义__eq__()方法。

@total_ordering

class Student:

def __init__(self, lastname, firstname):

self.lastname = lastname

self.firstname = firstname

def _is_valid_operand(self, other):

return (hasattr(other, "lastname") and

hasattr(other, "firstname"))

def __eq__(self, other):

if not self._is_valid_operand(other):

return NotImplemented

return ((self.lastname.lower(), self.firstname.lower()) ==

(other.lastname.lower(), other.firstname.lower()))

def __lt__(self, other):

if not self._is_valid_operand(other):

return NotImplemented

return ((self.lastname.lower(), self.firstname.lower()) <

(other.lastname.lower(), other.firstname.lower()))

NOTE:使用这个装饰器的代价是,装饰器自动补足的比较方法耗费了更多的执行时间并拥有更复杂的堆栈跟踪。如果应用性能基准测试表明是使用此装饰器造成的瓶颈,手动实现所有六种富比较方法可以带来直观的速度提升。

functools.partial(func, *args, **keywords)

偏函数,返回一个partial对象,调用时等同调用了使用预设位置参数和关键字参数的func函数。如果partial对象调用时又提供了额外的位置参数,追加到args,如果提供了额外的关键字参数,扩展keywords并覆盖相同的键值。

大致等同于:

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

partial()用于"冻结"函数的部分位置参数和/或关键字参数而产生一个代表某部分函数功能的简化标志。

>>> from functools import partial

>>> basetwo = partial(int, base=2)

>>> basetwo.__doc__ = 'Convert base 2 string to an int.'

>>> basetwo('10010')

18

class functools.partialmethod(func, *args, **keywords)

后续补充

functools.reduce(function, iterable[, initializer])

将可迭代对象iterable中的元素从左到右累计到接收两个参数的函数func中。例如reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])的计算等同于((((1+2)+3)+4)+5)。

如果设置了可选参数initializer,它被放置在要计算的序列之前,并在序列为空时作为默认值;如果未提供initializer的值且序列仅包含一个元素,返回该元素。

@functools.singledispatch

将函数转换为单分派泛函数(single-dispatch generic function)。

使用@singledispatch装饰器定义一个泛函数,单分派仅限于第一个参数的类型:

from functools import singledispatch

@singledispatch

def fun(arg, verbose=False):

if verbose:

print("Let me just say,", end=" ")

print(arg)

使用泛函数的register()属性添加重载实现,该属性是一个装饰器。对于使用类型注解的函数,该装饰器将自动推断第一个参数的类型:

@fun.register

def _(arg: int, verbose=False):

if verbose:

print("Strength in numbers, eh?", end=" ")

print(arg)

@fun.register

def _(arg: list, verbose=False):

if verbose:

print("Enumerate this:")

for i, elem in enumerate(arg):

print(i, elem)

如果不使用类型注解,可以显式地给装饰器传递类型参数:

@fun.register(complex)

def _(arg, verbose=False):

if verbose:

print("Better than complicated.", end=" ")

print(arg.real, arg.imag)

也可以以函数的形式使用register()注册lambda函数和已定义的函数:

def nothing(arg, verbose=False):

print("Nothing.")

fun.register(type(None), nothing)

register()属性返回允许装饰器堆叠、序列化以及创建独立的单元测试的未装饰的函数:

from decimal import Decimal

@fun.register(float)

@fun.register(Decimal)

def fun_num(arg, verbose=False):

if verbose:

print("Half of your number:", end=" ")

print(arg / 2)

>>> fun_num is fun

False

调用时,泛函数只分派第一个参数的类型:

>>> fun("Hello, world.")

Hello, world.

>>> fun("test.", verbose=True)

Let me just say, test.

>>> fun(42, verbose=True)

Strength in numbers, eh? 42

>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)

Enumerate this:

0 spam

1 spam

2 eggs

3 spam

>>> fun(None)

Nothing.

>>> fun(1.23)

0.615

如果某个类型没有相应的实现,将查找更通用的实现进行解析。使用@singledispatch装饰的原始函数注册为object类型,将在没有更好实现的情况下使用。调用dispatch()属性查看泛函数使用了哪个实现:

>>> fun.dispatch(float)

>>> fun.dispatch(dict) # note: default implementation

调用registry属性查看注册的所有实现:

>>> fun.registry.keys()

dict_keys([, , , , , ])

>>> fun.registry[float]

>>> fun.registry[object]

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

更新包装函数(wrapper),使其看起来更像被包装的原始函数(wrapped)。元组类型的可选参数assigned指定wrapped函数的哪些属性直接分派到wrapper函数对应的属性上,updated参数指定使用wrapped函数的哪些属性更新wrapper函数对应的属性。

WRAPPER_ASSIGNMENTS的默认值是'__module__', '__name__', '__qualname__', '__doc__','__annotations__'

WRAPPER_UPDATES的默认值是'__dict__'

通过访问包装函数的__wrapped__属性可以获取到被包装的原始函数。

该函数主要用于装饰器使用场景下,如果不更新包装函数,返回函数的元数据将指向包装函数而非被包装的原始函数,一般来说没太大意义。

def wrapper(f):

def wrapper_function(*args, **kwargs):

"""this is a wrapper function"""

return f(*args, **kwargs)

# update_wrapper(wrapper_function, f)

return wrapper_function

@wrapper

def wrapped():

"""this is a wrapped function"""

pass

print(wrapped.__doc__)

print(wrapped.__name__)

# 不使用update_wrapper的结果:

>>> this is a wrapper function

>>> wrapper_function

# 使用update_wrapper的结果:

>>> this is a wrapped function

>>> wrapped

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

等同于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated),不过是作为包装函数定义时的装饰器使用。

def wrapper(f):

@wraps(f)

def wrapper_function(*args, **kwargs):

"""this is a wrapper function"""

return f(*args, **kwargs)

return wrapper_function

@wrapper

def wrapped():

"""this is a wrapped function"""

pass

print(wrapped.__doc__)

print(wrapped.__name__)

partial对象

partial对象是由partial()方法创建的可调用对象,它有三个只读属性:

partial.func

一个可调用对象或函数。调用partial对象将使用新的位置参数和关键字参数转发到func。

partial.args

调用partial()时提供的位置参数

partial.keywords

调用partial()时提供的关键字参数

python中functools_python模块之functools相关推荐

  1. python中导入模块用什么命令_Python导入模块的技巧

    作为使用Python的开发者,我们一开始学习的内容之一就是如何导入Python的各种模块或库.但是我们注意到,那些经常使用Python的用户并不一定都知道Python的导入机制其实非常灵活.在本文中, ...

  2. python sys模块作用_浅谈Python中的模块

    模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...

  3. python中Scipy模块求取积分

    python中Scipy模块求取积分的方法: SciPy下实现求函数的积分的函数的基本使用,积分,高等数学里有大量的讲述,基本意思就是求曲线下面积之和. 其中rn可认为是偏差,一般可以忽略不计,wi可 ...

  4. python中的time库安装步骤-python中time模块需要安装么

    time是python自带的模块,用于处理时间问题,提供了一系列的操作时间的函数. time模块中时间表现的格式主要有三种:(推荐学习:Python视频教程) timestamp时间戳,是以秒表示从& ...

  5. 关于python中requests模块导入问题-python中requests模块的使用方法

    本文实例讲述了python中requests模块的使用方法.分享给大家供大家参考.具体分析如下: 在HTTP相关处理中使用python是不必要的麻烦,这包括urllib2模块以巨大的复杂性代价获取综合 ...

  6. python哪里下载import包-详解python中的模块及包导入

    python中的导入关键字:import 以及from import 1.import import一般用于导入包以及模块. 不过有个小问题: (1)当导入的是模块的时候是可以直接可以使用模块内的函数 ...

  7. python中copy模块的使用,深拷贝和浅拷贝

    python中copy模块的使用,深拷贝和浅拷贝 文章目录: 一.copy模块的介绍 1.copy模块 二.copy模块的使用 拓展说明: 1.id( )函数的使用 2.is和== 的区别 pytho ...

  8. python中的模块和包

    模块 一 什么是模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能. 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使 ...

  9. python中pyecharts模块全局配置_python中pyecharts模块的使用示例

    python中pyecharts模块的使用示例 发布时间:2020-11-24 09:28:53 来源:亿速云 阅读:66 作者:小新 小编给大家分享一下python中pyecharts模块的使用示例 ...

最新文章

  1. 我所经历的京东618
  2. 微软职位内部推荐-Software Engineer II-Data Mini
  3. 读书笔记-《增长黑客》-低成本、高效率的精准营销
  4. CORS with Spring MVC--转
  5. rabbitmq实战_RabbitMQ 实战系列之:消息传递
  6. html/css学习笔记(一)
  7. Vue3---vue组件库
  8. Word 如何设置空白页
  9. 新手必学的Mac使用技巧
  10. Oracle SQL优化原则
  11. Python_配置清华镜像源的方法
  12. jar error in opening zip file
  13. 液晶拼接大屏的日常维护与保养
  14. 修复常见ACPI问题(DSDT等)
  15. 西米推荐-FileYee:可能是最简单安全的数据文件备份软件
  16. qq linux for android,腾讯QQ for android 糊弄还是敷衍?
  17. 自动驾驶笔记-轨迹跟踪之①纯跟踪算法(Pure Pursuit)
  18. 四种连接类型:inner(内连接),left[outer](左外连接),right[outer](右外连接),full[outer](完全外连接)
  19. python3:urllib/urllib2
  20. Java基础—心型代码

热门文章

  1. C语言数组之斐波那契数列
  2. NAT模式下的虚拟机网络配置
  3. python 开课_python全栈学习1.开课介绍
  4. linux系统截图有快捷键吗,linux系统下ubuntu 中截图工具及快捷键设置
  5. 首次加载页面时,Android Chrome上永远不会触发Touchstart事件
  6. 华中农业大学信息管理与信息系统【信息安全与保密】实验报告
  7. max-width: 100%和width:100%的区别
  8. 港科30周年| 快来【特别定制】校庆专属头像
  9. Swagger3.0.0
  10. mysql 字段名排序_mysql 字段属性 与 排序