Python-Functools 函数讲解:让代码极简且实用!
2023-10-06 22:42:32
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):