Python functools 模块详解

内容分享3小时前发布
0 1 0

functools 模块是 Python 标准库中用于高阶函数的工具集,主要提供函数式编程的支持。下面详细介绍该模块的主要功能和使用方法。

1. 模块导入

import functools

2. reduce() 函数

reduce() 函数用于对序列中的元素进行累积操作。

基本用法:

import functools

# 计算阶乘
result = functools.reduce(lambda x, y: x * y, range(1, 6))
print(result)
# 输出: 120

# 字符串连接
words = ['Python', 'is', 'awesome']
sentence = functools.reduce(lambda x, y: x + ' ' + y, words)
print(sentence)
# 输出: Python is awesome

此代码部分语法与关键信息无需改动,已较为规范,仅在注释处可适当优化表述,以增强可读性与书面性。上述代码中,注释部分使用了“计算阶乘”“字符串连接”等表述,使代码的功能意图更加清晰明确。

Python functools 模块详解

带初始值:

# 具备初始值的累加操作
numbers = [1, 2, 3, 4]
total = functools.reduce(lambda x, y: x + y, numbers, 10)
print(total)
# 输出: 20 (即 10 + 1 + 2 + 3 + 4 之和)

3. partial() 函数

partial() 用于部分应用函数参数,创建新的可调用对象。

基本用法:

import functools

# 定义乘法函数
def multiply(x, y):
    return x * y

# 构建固定首个参数的新函数
double = functools.partial(multiply, 2)
print(double(5))
# 输出: 10

# 构建固定第二个参数的新函数
triple = functools.partial(multiply, y=3)
print(triple(4))
# 输出: 12

实际应用示例:

import functools

# 1. 简化函数调用
# 定义幂运算函数
def power(base, exponent):
    return base ** exponent

# 创建用于计算平方的函数
square = functools.partial(power, exponent=2)
# 创建立方函数
cube = functools.partial(power, exponent=3)

print(square(5))
# 输出: 25
print(cube(3))
# 输出: 27

# 2. 处理默认参数
# 定义问候函数
def greet(name, message="Hello"):
    return f"{message}, {name}!"

# 创建特定的问候函数
say_hello = functools.partial(greet, message="Hello")
say_hi = functools.partial(greet, message="Hi")
say_hey = functools.partial(greet, message="Hey")

print(say_hello("Alice"))
# 输出: Hello, Alice!
print(say_hi("Bob"))
# 输出: Hi, Bob!

4. lru_cache 装饰器

lru_cache 提供最近最少使用缓存,用于函数结果缓存,提升性能。

基本用法:

import functools
import time

# 运用 LRU 缓存机制对斐波那契函数进行优化
@functools.lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

# 开展性能测试
start_time = time.time()
result = fibonacci(35)
end_time = time.time()

print(f"斐波那契数列第 35 项的值为: {result}")
print(f"此次计算耗时: {end_time - start_time:.4f} 秒")

缓存参数配置:

import functools

# 配置无大小限制的缓存机制
@functools.lru_cache(maxsize=None)
def expensive_operation(x):
    print(f"正在计算 {x}...")
    return x * x

# 进行功能测试
print(expensive_operation(5))
# 首次调用,会打印“正在计算 5...”
print(expensive_operation(5))
# 后续调用,直接从缓存返回结果,不会再次打印计算信息

# 配置带参数的缓存机制,最大缓存容量为 32
@functools.lru_cache(maxsize=32)
def configurable_operation(a, b, option=True):
    print(f"正在执行操作: a={a}, b={b}, option={option}")
    return a + b if option else a * b

print(configurable_operation(2, 3))
# 首次调用,会执行计算并打印操作信息
print(configurable_operation(2, 3))
# 一样参数的后续调用,从缓存返回结果
print(configurable_operation(2, 3, False))
# 不同参数的调用,会重新执行计算

5. wraps 装饰器

wraps 用于保留被装饰函数的元数据。

问题演示:

# 定义装饰器函数
def my_decorator(func):
    def wrapper(*args, **kwargs):
        """此为包装器的文档说明"""
        return func(*args, **kwargs)
    return wrapper

# 使用装饰器修饰示例函数
@my_decorator
def example():
    """这是示例函数的文档说明"""
    pass

# 打印函数的名称和文档字符串
print(example.__name__)
# 输出: wrapper
print(example.__doc__)
# 输出: 此为包装器的文档说明

使用 wraps 解决问题:

import functools

# 定义装饰器函数,借助 functools.wraps 保留原函数元信息
def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        """此为包装器的详细文档说明"""
        return func(*args, **kwargs)
    return wrapper

# 使用自定义装饰器修饰示例函数
@my_decorator
def example():
    """这是示例函数的详尽文档说明"""
    pass

# 打印函数的名称和文档字符串,因使用 wraps 保留元信息,输出为原函数相关内容
print(example.__name__)
# 输出: example
print(example.__doc__)
# 输出: 这是示例函数的详尽文档说明

6. total_ordering 装饰器

total_ordering 自动生成缺失的比较方法。

基本用法:

import functools

# 运用 functools.total_ordering 装饰器,为类自动生成比较方法
@functools.total_ordering
class Student:
    def __init__(self, name, score):
        # 初始化学生对象,包含姓名和分数属性
        self.name = name
        self.score = score

    def __eq__(self, other):
        # 定义相等比较方法,依据学生分数来判断
        return self.score == other.score

    def __lt__(self, other):
        # 定义小于比较方法,根据学生分数进行比较
        return self.score < other.score

# 创建两个学生对象
student1 = Student("Alice", 85)
student2 = Student("Bob", 92)

# 进行各种比较操作并输出结果
print(student1 < student2)
# 输出: True
print(student1 <= student2)
# 输出: True
print(student1 > student2)
# 输出: False
print(student1 >= student2)
# 输出: False
print(student1 == student2)
# 输出: False

7. cmp_to_key 函数

cmp_to_key 将老式比较函数转换为 key 函数。

使用示例:

import functools

# 定义老式的比较函数,通过两数相减来判断大小关系
def numeric_compare(x, y):
    return x - y

# 构建现代风格的比较函数,以 -1、1 和 0 明确表明大小关系
def modern_compare(x, y):
    """此为现代风格的比较函数,用于比较两个元素的大小"""
    if x < y:
        return -1
    elif x > y:
        return 1
    else:
        return 0

# 准备待排序的数字列表
numbers = [5, 2, 8, 1, 9]

# 利用 functools.cmp_to_key 将现代比较函数转换为适用于 sorted 函数的 key 函数进行排序
sorted_numbers = sorted(numbers, key=functools.cmp_to_key(modern_compare))
print(sorted_numbers)
# 输出按升序排列的数字列表:[1, 2, 5, 8, 9]

# 定义复杂的自定义比较函数,先按元素长度比较,长度一样时再按字母顺序比较
def custom_compare(a, b):
    """该比较函数先比较元素的长度,若长度不同则按长度排序;长度一样时,再按字母顺序排序"""
    if len(a) != len(b):
        return len(a) - len(b)
    elif a < b:
        return -1
    elif a > b:
        return 1
    else:
        return 0

# 准备待排序的单词列表
words = ['apple', 'banana', 'cherry', 'date', 'elderberry']

# 同样使用 functools.cmp_to_key 转换自定义比较函数后对单词列表进行排序
sorted_words = sorted(words, key=functools.cmp_to_key(custom_compare))
print(sorted_words)

8. singledispatch 装饰器

singledispatch 实现函数重载(单分派泛函数)。

基本用法:

import functools

# 运用 functools.singledispatch 实现单分派泛函数
@functools.singledispatch
def process(arg):
    """
    此为默认的处理函数,当传入的参数类型未被其他注册函数匹配时执行
    """
    print(f"执行默认处理流程: {arg}")

# 注册针对整数类型的处理函数
@process.register
def _(arg: int):
    """
    专门处理整数类型参数的函数
    """
    print(f"针对整数进行处理: {arg}")

# 注册针对字符串类型的处理函数
@process.register
def _(arg: str):
    """
    专门处理字符串类型参数的函数
    """
    print(f"针对字符串进行处理: {arg}")

# 注册针对列表类型的处理函数
@process.register
def _(arg: list):
    """
    专门处理列表类型参数的函数,会输出列表的长度
    """
    print(f"对列表进行处理,其长度为: {len(arg)}")

# 测试不同类型参数的处理情况
process(42)
# 输出: 针对整数进行处理: 42
process("hello")
# 输出: 针对字符串进行处理: hello
process([1, 2, 3])
# 输出: 对列表进行处理,其长度为: 3
process(3.14)
# 输出: 执行默认处理流程: 3.14

9. 实际应用案例

案例 1:性能优化缓存

import functools
import time

# 利用 functools.lru_cache 装饰器,设置最大缓存大小为 100,对函数结果进行缓存
@functools.lru_cache(maxsize=100)
def expensive_api_call(user_id):
    """
    此函数用于模拟一次代价高昂的 API 调用,会产生必定的网络延迟
    """
    time.sleep(1)  # 模拟网络延迟所耗费的时间
    return f"用户 {user_id} 的相关数据"

# 测试缓存机制的实际效果
start_time = time.time()

# 首次调用函数,由于没有缓存,会执行完整的 API 调用流程,大约耗时 1 秒
print(expensive_api_call(1))

# 再次以一样参数调用函数,此时结果已被缓存,会直接从缓存中获取,几乎瞬间完成
print(expensive_api_call(1))

# 传入新的参数调用函数,由于缓存中没有该结果,会再次执行完整的 API 调用,大约耗时 1 秒
print(expensive_api_call(2))

end_time = time.time()

# 输出整个测试过程所花费的总时间,保留两位小数
print(f"总耗时: {end_time - start_time:.2f} 秒")

案例 2:装饰器工具函数

import functools
import time

# 定义计时装饰器,用于准确测量函数的执行时间
def timer(func):
    """
    此为计时装饰器,可准确记录并输出被装饰函数的执行时长
    """
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 记录函数开始执行的时间
        start_time = time.time()
        # 调用被装饰的函数并获取结果
        result = func(*args, **kwargs)
        # 记录函数执行结束的时间
        end_time = time.time()
        # 输出函数执行的时间,准确到小数点后四位
        print(f"函数 {func.__name__} 的执行时间为: {end_time - start_time:.4f} 秒")
        return result
    return wrapper

# 定义重试装饰器,允许函数在执行失败时进行重试
def retry(max_attempts=3, delay=1):
    """
    此为重试装饰器,当被装饰的函数执行出现异常时,会尝试重新执行指定次数
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 循环尝试执行函数,最多尝试 max_attempts 次
            for attempt in range(max_attempts):
                try:
                    # 尝试执行被装饰的函数
                    return func(*args, **kwargs)
                except Exception as e:
                    # 如果达到最大尝试次数,抛出异常
                    if attempt == max_attempts - 1:
                        raise e
                    # 输出当前尝试失败的信息,并提示将在指定延迟后重试
                    print(f"第 {attempt + 1} 次尝试失败,将在 {delay} 秒后重试,错误信息为: {e}")
                    # 等待指定的延迟时间
                    time.sleep(delay)
            return None
        return wrapper
    return decorator

# 使用计时装饰器和重试装饰器装饰不可靠操作函数
@timer
@retry(max_attempts=3, delay=1)
def unreliable_operation():
    """
    该函数用于模拟一个不可靠的操作,有必定概率执行失败
    """
    import random
    # 以 70% 的概率抛出异常
    if random.random() < 0.7:
        raise Exception("随机失败")
    return "操作成功"

# 测试不可靠操作函数
print(unreliable_operation())

案例 3:函数组合

import functools

# 定义函数组合功能,该功能允许将多个函数按照从右到左的顺序依次嵌套调用
# 例如,compose(f, g, h)(x) 等价于 f(g(h(x)))
def compose(*functions):
    """
    此函数实现了函数组合的功能,可按照传入函数的顺序,将多个函数进行组合。
    组合后的函数会依次对输入参数执行各函数的操作。
    """
    return functools.reduce(lambda f, g: lambda x: f(g(x)), functions)

# 定义几个简单的基础函数

# 该函数用于对输入的数值加 1
def add_one(x):
    return x + 1

# 此函数用于将输入的数值乘以 2
def multiply_by_two(x):
    return x * 2

# 该函数用于计算输入数值的平方
def square(x):
    return x ** 2

# 进行函数组合操作,将 add_one、multiply_by_two 和 square 这三个函数进行组合
# 组合后的函数按照 square -> multiply_by_two -> add_one 的顺序对输入进行处理
complex_operation = compose(add_one, multiply_by_two, square)

# 调用组合后的函数,传入参数 3,并获取计算结果
result = complex_operation(3)

# 输出最终的计算结果
print(f"计算结果为: {result}")
# 详细计算过程为:3 的平方是 9,9 乘以 2 得到 18,18 加 1 等于 19

10. 缓存统计信息

对于 lru_cache,可以查看缓存统计信息:

import functools

# 定义一个带有缓存功能的函数,使用 functools.lru_cache 装饰器,设置最大缓存大小为 3
# 该函数用于计算输入参数的平方
@functools.lru_cache(maxsize=3)
def cached_function(x):
    return x * x

# 调用该函数,依次传入不同的参数
cached_function(1)
cached_function(2)
cached_function(3)

# 再次传入之前使用过的参数 1,此时应命中缓存
cached_function(1)

# 传入新的参数 4,由于缓存已满,会触发缓存淘汰机制
cached_function(4)

# 查看当前缓存的相关信息,包括命中次数、未命中次数、最大缓存大小和当前缓存大小
print(f"当前缓存信息为: {cached_function.cache_info()}")
# 预期输出示例: CacheInfo(hits=1, misses=4, maxsize=3, currsize=3)

# 清空缓存中的所有条目
cached_function.cache_clear()

# 再次查看缓存信息,此时命中次数、未命中次数和当前缓存大小应重置为 0
print(f"缓存清空后信息为: {cached_function.cache_info()}")
# 预期输出: CacheInfo(hits=0, misses=0, maxsize=3, currsize=0)

Python functools 模块详解

总结

functools 模块提供了强劲的函数式编程工具:

  • reduce(): 序列累积操作
  • partial(): 部分应用函数参数
  • lru_cache: 函数结果缓存,提升性能
  • wraps: 保留装饰函数的元数据
  • total_ordering: 自动生成比较方法
  • cmp_to_key: 转换老式比较函数
  • singledispatch: 函数重载支持

这些工具使得 Python 代码更加简洁、高效和可维护,特别适合函数式编程风格和性能优化场景。

© 版权声明

相关文章

1 条评论

  • 头像
    大侠biu 投稿者

    收藏了,感谢分享

    无记录
    回复