深入理解 Python 中的装饰器(Decorator)及其应用
在 Python 中,装饰器(Decorator) 是一种强大的功能,可以让我们在不修改原始函数代码的情况下,动态地为函数添加额外的功能。它广泛应用于日志记录、权限校验、缓存管理等场景,是 Python 编程中一个非常有用的工具。
本文将深入探讨 Python 中的装饰器,包括其定义、使用场景、以及一些常见的高级用法。
1. 什么是装饰器?
装饰器本质上是一个函数,它接受一个函数作为输入,返回一个新的函数。这个新的函数通常会在原始函数的基础上添加一些额外的功能。
简单例子:
def decorator(func):
def wrapper():
print("Before function execution.")
func() # 调用原始函数
print("After function execution.")
return wrapper
# 被装饰的函数
@decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Before function execution.
Hello!
After function execution.
解释:
@decorator
语法是装饰器的简写形式。它相当于 say_hello = decorator(say_hello)
。2. 装饰器的应用场景
装饰器的强大之处在于它能在不修改函数的情况下为函数添加新的功能。以下是常见的几种应用场景:
2.1. 日志记录
我们可以使用装饰器为函数添加日志记录功能,这样就能自动记录每次函数调用的时间、参数和返回值。
import time
def log(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function '{func.__name__}' executed in {end_time - start_time:.4f} seconds.")
return result
return wrapper
@log
def slow_function():
time.sleep(2)
return "Finished!"
slow_function()
输出:
Function 'slow_function' executed in 2.0001 seconds.
2.2. 权限检查
我们还可以用装饰器来检查用户是否有权限执行某个操作。
def require_permission(func):
def wrapper(user, *args, **kwargs):
if user != "admin":
print("Permission denied!")
return
return func(user, *args, **kwargs)
return wrapper
@require_permission
def delete_user(user):
print(f"User {user} deleted!")
delete_user("admin") # 有权限
delete_user("guest") # 没有权限
输出:
User admin deleted!
Permission denied!
2.3. 缓存
装饰器还常用于实现函数结果的缓存,即对于相同的输入,返回相同的结果,而不需要每次都重新计算。
def cache(func):
cached_results = {}
def wrapper(*args):
if args in cached_results:
print("Fetching from cache...")
return cached_results[args]
result = func(*args)
cached_results[args] = result
return result
return wrapper
@cache
def slow_function(n):
print(f"Calculating {n}...")
time.sleep(2)
return n * 2
print(slow_function(3)) # 第一次执行
print(slow_function(3)) # 第二次从缓存中取值
输出:
Calculating 3...
6
Fetching from cache...
6
3. 装饰器的嵌套使用
我们可以将多个装饰器应用到同一个函数,这样可以让函数在不同层次上执行多个功能。
def decorator1(func):
def wrapper(*args, **kwargs):
print("Decorator 1")
return func(*args, **kwargs)
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print("Decorator 2")
return func(*args, **kwargs)
return wrapper
@decorator1
@decorator2
def greet():
print("Hello!")
greet()
输出:
Decorator 1
Decorator 2
Hello!
解释:
@decorator2
先应用,然后 @decorator1
再应用。4. 带参数的装饰器
有时我们需要传递参数给装饰器,这样可以定制装饰器的行为。我们需要使用多层嵌套来实现这一点。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
输出:
Hello!
Hello!
Hello!
解释:
repeat(3)
返回一个装饰器,装饰器再接收 say_hello
函数并包装起来。最终,say_hello
会被调用 3 次。5. functools.wraps 和装饰器的元信息
当我们使用装饰器时,原始函数的元数据(如函数名、文档字符串)会被包装成装饰器中的内部函数,从而丧失。这时我们可以使用 functools.wraps
来保留这些元信息。
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Function is called!")
return func(*args, **kwargs)
return wrapper
@decorator
def greet(name):
"""This function greets the person."""
print(f"Hello, {name}!")
print(greet.__name__) # 输出 greet
print(greet.__doc__) # 输出 This function greets the person.
输出:
greet
This function greets the person.
解释:
@functools.wraps(func)
确保 greet
函数的名称和文档字符串不会被装饰器中的 wrapper
函数覆盖。6. 结论
装饰器是 Python 中一个非常强大的工具,它能让我们在不修改原始函数代码的情况下为函数添加新的功能。常见的应用场景包括日志记录、权限校验、缓存管理等。掌握装饰器的用法,将大大提高代码的灵活性和可维护性。
装饰器的总结:
functools.wraps
保持函数的元数据。掌握装饰器的使用,你将能编写更加简洁、可复用且具有扩展性的代码! 😃
作者:小白8990