返回

Python-Functools 函数讲解:让代码极简且实用!

闲谈

Functools 是Python标准库中的一个模块,可帮助我们简洁地实现一些常见任务,包括编写装饰器、高效实现记忆化函数、处理迭代器和可迭代对象等。本文将介绍 Functools 中的11个函数及其用法,使您的代码更加优雅实用。




1. @functools.wraps

我们使用 Python 装饰器作为一种简单的在函数执行前或后增加其他逻辑的方法,来让代码变得更加简洁。@functools.wraps装饰器可确保装饰器函数能够保留原函数名称、函数文档和函数参数信息。

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 在此添加额外的逻辑
        result = func(*args, **kwargs)
        # 在此添加额外的逻辑
        return result
    return wrapper

@my_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")
# 输出: Hello, Alice!

如上所示,my_decorator装饰器被应用于greet函数,当我们调用greet("Alice")时,它不仅执行了greet函数,还执行了装饰器中添加的额外逻辑。同时,由于使用了@functools.wraps装饰器,greet函数仍然保留了其名称、文档和参数信息。

2. functools.update_wrapper

functools.update_wrapper用于将被装饰函数的名称、文档字符串和参数列表等属性复制到装饰器函数。

def my_decorator(func):
    functools.update_wrapper(func, my_decorator)
    # 在此添加额外的逻辑
    return func

@my_decorator
def greet(name):
    """向某人打招呼"""
    print(f"Hello, {name}!")

greet("Alice")
# 输出: Hello, Alice!

如上所示,我们使用functools.update_wrapper确保装饰器函数greet保留了被装饰函数greet的名称、文档字符串和参数列表等属性。

3. functools.reduce

functools.reduce用于对集合中的所有元素进行累积操作,返回单个结果。

from functools import reduce

numbers = [1, 2, 3, 4, 5]
result = reduce(lambda x, y: x + y, numbers)
# result = 15

如上所示,reduce使用lambda表达式作为累积函数,将numbers列表中的所有元素相加,并返回结果。

4. functools.partial

functools.partial用于创建函数的一部分应用形式,该部分应用形式可以作为新的函数进行调用。

from functools import partial

def greet(name, message):
    print(f"{message}, {name}!")

greet_alice = partial(greet, name="Alice")
greet_alice("Hello")
# 输出: Hello, Alice!

如上所示,我们使用partial创建了一个部分应用形式greet_alice,它绑定了greet函数的第一个参数name为"Alice",然后我们就可以使用greet_alice("Hello")调用它。

5. functools.cmp_to_key

functools.cmp_to_key将比较函数转换为键函数,以便可以在sorted()函数中使用。

from functools import cmp_to_key

def compare_by_length(a, b):
    return len(a) - len(b)

words = ["short", "very_long", "medium"]
sorted_words = sorted(words, key=cmp_to_key(compare_by_length))
# sorted_words = ['short', 'medium', 'very_long']

如上所示,我们使用cmp_to_key将compare_by_length比较函数转换为键函数,然后使用sorted()函数对words列表进行排序。

6. functools.lru_cache

functools.lru_cache用于对函数进行记忆化,即将函数的输入输出对存储在一个字典中,以便在下次调用时直接从字典中获取结果,从而提高性能。

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(35))
# 输出: 9227465

如上所示,我们使用lru_cache对fibonacci函数进行了记忆化,当我们调用fibonacci(35)时,它先检查字典中是否已经存在fibonacci(35)的结果,如果没有,则计算结果并将其存储在字典中,然后返回结果。

7. functools.total_ordering

functools.total_ordering用于将一个类标记为可比较的,以便它可以被比较运算符(<, >, <=, >=, ==, !=)使用。

from functools import total_ordering

@total_ordering
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    def __lt__(self, other):
        return self.age < other.age

people = [
    Person("Alice", 25),
    Person("Bob", 30),
    Person("Charlie", 20)
]
people.sort()
# people = [Person('Charlie', 20), Person('Alice', 25), Person('Bob', 30)]

如上所示,我们使用total_ordering标记Person类为可比较的,然后我们就可以对people列表进行排序。

8. functools.singledispatch

functools.singledispatch用于将函数分派到不同的实现上,具体实现取决于参数的类型。

from functools import singledispatch

@singledispatch
def greet(obj):
    print(f"Hello, {obj}!")

@greet.register(list)
def _(obj):
    print(f"Hello, {obj[0]} and friends!")

greet("Alice")
# 输出: Hello, Alice!

greet(["Alice", "Bob", "Charlie"])
# 输出: Hello, Alice and friends!

如上所示,我们使用singledispatch将greet函数分派到不同的实现上,具体实现取决于参数的类型。当我们调用greet("Alice")时,它调用了默认的greet函数,当我们调用greet(["Alice", "Bob", "Charlie"])时,它调用了greet.register(list)函数。

9. functools.cache

functools.cache用于对函数进行记忆化,与lru_cache不同的是,cache不限制缓存的大小,并且它使用最近最少使用 (LRU) 算法来管理缓存。

from functools import cache

@cache
def fibonacci(n):
    if n < 2:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(35))
# 输出: 9227465

如上所示,我们使用cache对fibonacci函数进行了记忆化,当我们调用fibonacci(35)时,它先检查缓存中是否已经存在fibonacci(35)的结果,如果没有,则计算结果并将其存储在缓存中,然后返回结果。

10. functools.wraps

functools.wraps用于将被装饰函数的名称、文档字符串和参数列表等属性复制到装饰器函数。

def my_decorator(func):
    functools.wraps(func)
    # 在此添加额外的逻辑
    return func

@my_decorator
def greet(name):
    """向某人打招呼"""
    print(f"Hello, {name}!")

greet("Alice")
# 输出: Hello, Alice!

如上所示,我们使用functools.wraps确保装饰器函数greet保留了被装饰函数greet的名称、文档字符串和参数列表等属性。

11. functools.update_wrapper

functools.update_wrapper用于将被装饰函数的名称、文档字符串和参数列表等属性复制到装饰器函数。

import functools

def my_decorator(func):
    @functools.update_wrapper(func)
    def wrapper(*args, **kwargs):