Python的functools模块完全教程

news/2024/10/11 18:47:25/

python函数是一等公民。Java中则为类是一等公民

当一个函数将另一个函数作为输入或返回另一个函数作为输出时,这些函数称为高阶函数

functools模块是Python的标准库的一部分,它是为高阶函数而实现的,用于增强函数功能

目录

一、@cache装饰器

二、@cached_property装饰器

三、@lru_cache装饰器

四、 partial函数

五、partialmethod函数

六、@singledispatch装饰器

七、@singledispatchmethod装饰器

八、update_wrapper与wraps函数


一、@cache装饰器

它的主要作用是提高函数的执行效率,特别是在函数被多次调用且输入参数相同的情况下,避免重复计算,如果一个函数在相同的输入参数下被多次调用,cache 会记住第一次调用的结果,并在后续调用中直接返回缓存的结果,而不是重新计算

它是线程安全的,因此可以在多个线程中使用。'

python">from functools import cachedef factorial(n):print("无cache执行")return n@cache
def factorial_cache(n):print("执行cache")return nif __name__ == '__main__':for i in range(10):factorial(10)factorial_cache(10)

二、@cached_property装饰器

用于将一个类的无参方法转换为缓存属性,意味着该方法在第一次调用时会被计算并缓存结果,后续调用时直接返回缓存的结果。缓存的结果是实例级别的,即每个实例都有自己的缓存。即使后续改变了方法内部涉及的类参数,输出也结果不会发生改变。

python">from functools import cached_propertyclass Circle:def __init__(self, radius):self.radius = radius@cached_propertydef area(self):# 如果类本身存在area属性,则此方法不生效。也就是本身属性读取和写入优先于 cached_property 方法print("计算面积")return 3.14159 * self.radius ** 2if __name__ == '__main__':# 创建 Circle 对象circle = Circle(5)# 第一次访问 area 属性时会计算并缓存结果print(circle.radius, circle.area)del circle.radiuscircle.radius = 60# 第二次访问 area 属性时直接返回缓存的结果,即使是中途改变了圆的半径或者是删除了参与计算的参数。print(circle.radius, circle.area)

三、@lru_cache装饰器

lru_cache相较于cached_property,它装饰的方法是可以带参数的。

缓存是线程安全的,因此可以在 多个线程。

python">from functools import cached_property, lru_cacheclass Circle:def __init__(self, radius):self.radius = radius@lru_cache(maxsize=128)  # 缓存最大容量def area(self, precision):# 如果类本身存在area属性,则此方法不生效。也就是本身属性读取和写入优先于 cached_property 方法print("计算面积")return 3.14159 * self.radius ** precisionif __name__ == '__main__':# 创建 Circle 对象circle = Circle(5)# 第一次访问会计算并缓存结果print(circle.radius, circle.area(precision=2))# 第二次访问如果输入参数相同,则直接返回缓存的结果,如果输入参数不同,则重新计算并缓存。print(circle.radius, circle.area(precision=3))print(circle.radius, circle.area(precision=3))print(circle.radius, circle.area(precision=2))

四、 partial函数

它允许你固定一个或多个参数,从而创建一个新的函数,这个新函数在调用时只需要提供剩余的参数。
 

python">from functools import partial# 计算一个数的幂
def power(base, exponent):return base ** exponentif __name__ == '__main__':# 但是我们需要计算是平方,只需要传入具体的数字。所以使用 partial 来简化,产生一个新的函数square = partial(power, exponent=2)print(square(3))  # 输出: 9print(square(4))  # 输出: 16

用于函数组合,即将多个函数组合成一个新的函数。

python">from functools import partial# 加函数
def add(a, b):return a + b# 积函数
def multiply(a, b):return a * bif __name__ == '__main__':# 对函数进行组合,add函数的入参是固定的。我只需要它的结果作为乘积函数的入参。调用时只需要传入一个参数即可add_and_multiply = partial(multiply, add(2, 3))print(add_and_multiply(4))  # 输出: 20

简化回调函数

python">from functools import partialdef callback(a, b, c):print(f"a: {a}, b: {b}, c: {c}")if __name__ == '__main__':# 使用 partial 固定 a 和 b 参数fixed_callback = partial(callback, a=1, b=2)fixed_callback(c=3)  # 输出: a: 1, b: 2, c: 3

五、partialmethod函数

它与 partial 类似,但更适合用于类方法,因为它会正确处理 self 参数。

python">from functools import partialmethodclass Demo:def __init__(self, value):self.value = valuedef get_something(self, name, age):return (self.value, name, age)# 使用 partialmethod 定义一个部分应用的方法get_something_with_default = partialmethod(get_something, name="长期", age=16)if __name__ == '__main__':demo = Demo(value=1)print(demo.get_something(name=1, age=2))print(demo.get_something_with_default())

六、@singledispatch装饰器

它用于实现函数的多态性,即根据函数的第一个参数的类型来决定调用哪个具体的实现。singledispatch 允许你为一个函数定义多个实现,每个实现对应不同的参数类型。

一个非常有用的工具,特别是在你需要根据参数类型来选择不同实现的情况下。它使得代码更加清晰和可维护,避免了大量的条件判断。通过结合类型注解,singledispatch 可以进一步提高代码的可读性和可维护性。

python">from functools import singledispatch# 定义一个通用的函数
@singledispatch
def process(arg):return f"Processing generic argument: {arg}"# 为 int 类型定义一个特定的实现
@process.register
def _(arg: int):return f"Processing integer: {arg}"# 为 str 类型定义一个特定的实现
@process.register(str)
def _(arg):return f"Processing string: {arg}"# 为 list 类型定义一个特定的实现
@process.register
def _(arg: list):return f"Processing list: {arg}"if __name__ == '__main__':# 调用不同类型的参数print(process(10))  # 输出: Processing integer: 10print(process("hello"))  # 输出: Processing string: helloprint(process([1, 2, 3]))  # 输出: Processing list: [1, 2, 3]print(process(3.14))  # 输出: Processing generic argument: 3.14

七、@singledispatchmethod装饰器

它与 singledispatch 类似,但专门用于类方法(class methods)

python">from functools import singledispatchmethodclass Demo:@singledispatchmethoddef process(self, arg):return f"Processing generic argument: {arg}"@process.registerdef _(self, arg: int):return f"Processing integer: {arg}"@process.registerdef _(self, arg: str):return f"Processing string: {arg}"@process.registerdef _(self, arg: list):return f"Processing list: {arg}"if __name__ == '__main__':# 创建类的实例demo = Demo()# 调用不同类型的参数print(demo.process(10))  # 输出: Processing integer: 10print(demo.process("hello"))  # 输出: Processing string: helloprint(demo.process([1, 2, 3]))  # 输出: Processing list: [1, 2, 3]print(demo.process(3.14))  # 输出: Processing generic argument: 3.14

八、update_wrapper与wraps函数

它用于更新一个包装函数(wrapper function)的元数据,使其看起来更像被包装的原始函数(wrapped function)。这在定义装饰器时非常有用,因为装饰器通常会返回一个新的函数,而这个新函数需要保留原始函数的元数据(如 __name__、__doc__、__module__ 等)

python">from functools import update_wrapperdef my_decorator(func):def wrapper(*args, **kwargs):print("Before function call")result = func(*args, **kwargs)print("After function call")return result# 使用 update_wrapper 更新 wrapper 的元数据update_wrapper(wrapper, func)return wrapper@my_decorator
def my_function():"""This is my function."""print("Inside my function")# 调用被装饰的函数
my_function()# 检查被装饰函数的元数据
print(my_function.__name__)  # 输出: my_function
print(my_function.__doc__)  # 输出: This is my function.

为了简化代码,functools 模块还提供了一个 wraps 装饰器,它实际上是 update_wrapper 的快捷方式。你可以使用 wraps 装饰器来代替手动调用 update_wrapper。

python">from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print("Before function call")result = func(*args, **kwargs)print("After function call")return resultreturn wrapper@my_decorator
def my_function():"""This is my function."""print("Inside my function")# 调用被装饰的函数
my_function()


http://www.ppmy.cn/news/1537580.html

相关文章

从零开始构建:Python自定义脚本自动化你的日常任务

从零开始构建:Python自定义脚本自动化你的日常任务 Python 作为一种简洁且功能强大的编程语言,被广泛应用于各种自动化任务中。通过编写 Python 脚本,你可以轻松地将日常重复性工作自动化,例如文件操作、数据处理、网络爬虫、系统…

Linux下Qt项目出现libQt5WebEngineCore.so报错

报错信息 :-1: error: Qt5.9.9/5.9.9/gcc_64/lib/libQt5WebEngineCore.so: .dynsym local symbol at index 3 (> sh_info of 3)解决办法如下: sudo ln -sf /usr/bin/x86_64-linux-gnu-ld.gold /usr/bin/ld命令解析: sudo:表示以超级用户&#xff0…

数据抓取对于动态代理IP有什么需求?

在当前这个数据驱动的世界中,数据抓取成为许多企业获取竞争优势的基本手段。然而,成功而高效地进行数据抓取,通常需要依赖于代理IP的使用,尤其是动态代理IP。动态代理IP以其灵活多变的特性,特别适合数据抓取中的多种需…

Linux中定时删除10天前的日志文件

例如:删除/data/log/目录下所有10天前的.log文件 find /data/log/ -type f -name "*.log" -mtime 10 -exec rm -f {} \;只查看要删除的文件有哪些,不真正删除文件 logfiles$(find /data/log/ -type f -name "*.log" -mtime 10) ec…

SpringCloud Config配置中心 SpringCloud Bus消息总线

一、SpringCloud Config 使用git储存配置信息 1)什么是 SpringCloud Config项目实现的目标是将配置文件从本地项目中抽出来放到git仓库中,项目启动时自动从git仓库中取配置文件。 但是本地项目不直接和git仓库通信,而是通过配置服务器中转。…

从零学编程- C语言-第18天

1.malloc 2.free 3.calloc 4.malloc 跟calloc 一个不能自动初始化一个能自动初始化 使用那个无所谓,看自己 calloc mallocmemset 5.realloc ​​​​​​​ ​​​​​​​ 6.申请空间是需要浪费时间的,频繁的添加空间耗时间,需要操作系…

JavaScript-上篇

JS 入门 JS概述 JavaScript(简称JS)是一种高层次、解释型的编程语言,最初由布兰登艾奇(Brendan Eich)于1995年创建,并首次出现在网景浏览器中。JS的设计初衷是为Web页面提供动态交互功能&#xff…

网站可疑问题

目标站点 Google hack 页面访问 抓包 POST /admin.php?actionlogin HTTP/2 Host: www.xjy.edu.cn Cookie: xkm_sidA6x4Cgw2zx User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0 Accept: text/html,application/xhtmlxml,appl…