简介
Python 装饰器是一个强大的工具,它允许你在不改变函数源代码的情况下修改函数的行为。在本教程中,我们将探讨如何在单个 Python 函数上使用多个装饰器,为代码重用和函数增强开辟一个充满可能性的世界。
Python 装饰器是一个强大的工具,它允许你在不改变函数源代码的情况下修改函数的行为。在本教程中,我们将探讨如何在单个 Python 函数上使用多个装饰器,为代码重用和函数增强开辟一个充满可能性的世界。
Python 中的装饰器是一种强大且灵活的方式,用于在不改变函数或类的源代码的情况下修改其行为。它们是用另一个函数“包装”一个函数的方法,使包装函数能够在原始函数被调用之前和/或之后执行代码。
装饰器可用于各种任务,例如:
Python 中的装饰器使用 @
符号定义,后面跟着装饰器函数。装饰器函数以一个函数作为参数,执行一些额外的处理,然后返回一个新的函数,该函数可以代替原始函数被调用。
下面是一个简单的装饰器函数示例,它记录传递给函数的参数:
def log_args(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args={args} and kwargs={kwargs}")
return func(*args, **kwargs)
return wrapper
@log_args
def add_numbers(a, b):
return a + b
result = add_numbers(2, 3)
print(result)
这将输出:
Calling add_numbers with args=(2, 3) and kwargs={}
5
装饰器可以嵌套,允许你对单个函数应用多个装饰器。装饰器的应用顺序很重要,因为它决定了装饰器函数的执行顺序。
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def reverse(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result[::-1]
return wrapper
@uppercase
@reverse
def greet(name):
return f"Hello, {name}!"
print(greet("LabEx"))
这将输出:
!XEbal,OLLEH
装饰器也可以接受参数,这使你能够自定义装饰器的行为。当你想要创建一个可以以不同方式配置的装饰器时,这很有用。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
result = ""
for _ in range(n):
result += func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
return f"Hello, {name}!"
print(greet("LabEx"))
这将输出:
Hello, LabEx!Hello, LabEx!Hello, LabEx!
当你对一个函数应用多个装饰器时,它们的应用顺序很重要。装饰器是从下往上应用的,这意味着最内层的装饰器首先被应用,最外层的装饰器最后被应用。
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def reverse(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result[::-1]
return wrapper
@uppercase
@reverse
def greet(name):
return f"Hello, {name}!"
print(greet("LabEx"))
这将输出:
!XEBAL,OLLEH
你也可以通过一个接一个地应用多个装饰器来堆叠它们。这等同于嵌套装饰器,但它可以使代码更具可读性。
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def reverse(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result[::-1]
return wrapper
def greet(name):
return f"Hello, {name}!"
greet_upper_reverse = uppercase(reverse(greet))
print(greet_upper_reverse("LabEx"))
这将输出:
!XEBAL,OLLEH
装饰器也可用于修改类中的方法的行为。同样的原则适用,但装饰器函数必须将 self
参数作为第一个参数。
def log_method(func):
def wrapper(self, *args, **kwargs):
print(f"Calling {func.__name__} on {self.__class__.__name__} with args={args} and kwargs={kwargs}")
return func(self, *args, **kwargs)
return wrapper
class Person:
def __init__(self, name):
self.name = name
@log_method
def greet(self, message):
return f"{message}, {self.name}!"
person = Person("LabEx")
print(person.greet("Hello"))
这将输出:
Calling greet on Person with args=('Hello',) and kwargs={}
Hello, LabEx!
装饰器也可用于修改整个类的行为。在这种情况下,装饰器函数以一个类作为参数,并返回一个具有所需行为的新类。
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class MyClass:
def __init__(self, value):
self.value = value
obj1 = MyClass(42)
obj2 = MyClass(24)
print(obj1 is obj2) ## True
print(obj1.value) ## 42
print(obj2.value) ## 42
在这个例子中,singleton
装饰器确保无论 MyClass
类被实例化多少次,都只会创建一个实例。
装饰器的一个常见用例是记录函数调用。这对于调试、监控或审计目的可能很有用。
def log_function_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args={args} and kwargs={kwargs}")
return func(*args, **kwargs)
return wrapper
@log_function_call
def add_numbers(a, b):
return a + b
result = add_numbers(2, 3)
print(result)
这将输出:
Calling add_numbers with args=(2, 3) and kwargs={}
5
装饰器还可用于缓存代价高昂的函数调用结果,从而提高性能。
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n <= 1:
return n
else:
return (fibonacci(n-1) + fibonacci(n-2))
print(fibonacci(100))
functools
模块中的 lru_cache
装饰器提供了一种简单的方法来为函数结果实现最近最少使用(LRU)缓存。
装饰器可用于对函数或方法实施访问控制,确保只有授权用户才能访问某些功能。
from functools import wraps
def require_admin(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not is_admin(args[0]):
raise ValueError("Access denied. You must be an admin.")
return func(*args, **kwargs)
return wrapper
class User:
def __init__(self, name, is_admin):
self.name = name
self.is_admin = is_admin
@require_admin
def delete_user(self, user_to_delete):
print(f"Deleting user: {user_to_delete.name}")
admin = User("LabEx", True)
regular_user = User("John", False)
admin.delete_user(regular_user) ## 可行
regular_user.delete_user(admin) ## 引发 ValueError
在这个示例中,require_admin
装饰器在允许操作继续之前,会检查调用 delete_user
方法的用户是否为管理员。
装饰器还可用于为可能因临时问题(如网络错误或 API 速率限制)而失败的函数实现重试机制。
import time
from functools import wraps
def retry(max_retries=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
retries = 0
while retries < max_retries:
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Function {func.__name__} failed. Retrying... ({retries+1}/{max_retries})")
retries += 1
time.sleep(delay)
raise Exception(f"Maximum number of retries ({max_retries}) reached for function {func.__name__}")
return wrapper
return decorator
@retry(max_retries=3, delay=2)
def flaky_function():
## 模拟一个有 50% 几率失败的不可靠函数
if random.random() < 0.5:
raise Exception("Oops, something went wrong!")
return "Success!"
print(flaky_function())
在这个示例中,retry
装饰器会在引发异常之前,自动对 flaky_function
重试最多 3 次,每次尝试之间延迟 2 秒。
这些只是 Python 中装饰器众多实际应用用例中的几个示例。装饰器是一个强大且灵活的工具,可以帮助你编写更模块化、可维护和可重用的代码。
在本教程结束时,你将对如何在单个 Python 函数上应用多个装饰器有扎实的理解。你将学习实际示例和现实世界中的用例,从而能够编写更模块化、灵活且易于维护的 Python 代码。