Python装饰器原理与实战全解
作者:第一程序员
这篇文章主要介绍了Python装饰器原理与实战,装饰器是Python中一种强大的特性,它允许我们以一种简洁、优雅的方式增强函数的功能,通过掌握装饰器的高级应用,我们可以编写更加模块化、可维护的代码
1. 装饰器基础
装饰器是 Python 中一种强大的特性,它允许我们在不修改原函数代码的情况下,增强函数的功能。
def decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@decorator
def greet(name):
print(f"Hello, {name}!")
# 调用被装饰的函数
greet("Alice")2. 带参数的装饰器
2.1 基本带参装饰器
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")2.2 装饰器类
class Timer:
def __init__(self, unit="seconds"):
self.unit = unit
def __call__(self, func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
duration = end - start
if self.unit == "milliseconds":
duration *= 1000
print(f"Function {func.__name__} took {duration:.2f} {self.unit}")
return result
return wrapper
@Timer(unit="milliseconds")
def slow_function():
import time
time.sleep(1)
print("Function executed")
slow_function()3. 高级装饰器技巧
3.1 保留函数元数据
使用 functools.wraps 可以保留被装饰函数的元数据。
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function"""
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@decorator
def greet(name):
"""Greet someone"""
print(f"Hello, {name}!")
print(greet.__name__) # 输出: greet
print(greet.__doc__) # 输出: Greet someone3.2 叠加装饰器
多个装饰器可以叠加使用,执行顺序是从下到上。
def decorator1(func):
def wrapper(*args, **kwargs):
print("Decorator 1 before")
result = func(*args, **kwargs)
print("Decorator 1 after")
return result
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print("Decorator 2 before")
result = func(*args, **kwargs)
print("Decorator 2 after")
return result
return wrapper
@decorator1
@decorator2
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
# 输出顺序:
# Decorator 1 before
# Decorator 2 before
# Hello, Alice!
# Decorator 2 after
# Decorator 1 after3.3 装饰器工厂
装饰器工厂是一个函数,它返回一个装饰器。
def create_decorator(prefix):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix}: Before function call")
result = func(*args, **kwargs)
print(f"{prefix}: After function call")
return result
return wrapper
return decorator
@create_decorator("DEBUG")
def greet(name):
print(f"Hello, {name}!")
greet("Alice")4. 实际应用场景
4.1 日志记录
import functools
import logging
logging.basicConfig(level=logging.INFO)
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
logging.info(f"{func.__name__} returned: {result}")
return result
return wrapper
@log
def add(a, b):
return a + b
result = add(1, 2)
print(result)4.2 缓存
import functools
def cache(func):
cache_dict = {}
@functools.wraps(func)
def wrapper(*args):
if args in cache_dict:
return cache_dict[args]
result = func(*args)
cache_dict[args] = result
return result
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(30)) # 第一次计算较慢
print(fibonacci(30)) # 第二次使用缓存,速度很快4.3 权限验证
import functools
def requires_permission(permission):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 假设 current_user 是当前登录用户
current_user = {"permissions": ["read", "write"]}
if permission not in current_user["permissions"]:
raise PermissionError(f"User does not have {permission} permission")
return func(*args, **kwargs)
return wrapper
return decorator
@requires_permission("write")
def create_post(title, content):
print(f"Creating post: {title}")
return {"title": title, "content": content}
@requires_permission("admin")
def delete_post(post_id):
print(f"Deleting post: {post_id}")
return True
create_post("Hello", "World") # 成功
# delete_post(1) # 抛出 PermissionError4.4 性能分析
import functools
import time
def performance(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@performance
def slow_function():
time.sleep(1)
return "Done"
slow_function()5. 最佳实践
- 使用
functools.wraps:保留被装饰函数的元数据,如函数名、文档字符串等。 - 保持装饰器简单:装饰器应该专注于单一功能,避免过于复杂。
- 使用参数化装饰器:对于需要配置的装饰器,使用参数化装饰器可以提高灵活性。
- 注意装饰器的执行顺序:当使用多个装饰器时,注意它们的执行顺序。
- 测试装饰器:确保装饰器在各种情况下都能正常工作。
- 文档化装饰器:为装饰器添加文档字符串,说明其功能和用法。
- 避免修改函数签名:装饰器应该保持函数的签名不变。
6. 总结
装饰器是 Python 中一种强大的特性,它允许我们以一种简洁、优雅的方式增强函数的功能。通过掌握装饰器的高级应用,我们可以编写更加模块化、可维护的代码。
在实际应用中,装饰器可以用于日志记录、缓存、权限验证、性能分析等多种场景,大大提高代码的复用性和可维护性。
希望本文对你理解和应用 Python 装饰器有所帮助!
以上就是Python装饰器原理与实战全解的详细内容,更多关于Python装饰器的资料请关注脚本之家其它相关文章!
