1. 关于装饰器这一概念的基本知识, 其中的第一小节内容探讨了这样一个问题, 即究竟什么是装饰器?
装饰器属于一种设计模式, 这种设计模式允许在不修改原始函数代码的前提情况下, 往函数内部添加全新的功能内容, 它属于语法糖的一种范畴, 是基于闭包机制以及高阶函数来实现相关效果的。
1.第2点, 装饰器究竟是什么东西。
从本质上来讲, 这个可调用对象就是装饰器。它的主要功能是接收一个函数当作参数。然后它会返回一个新的函数给你。
def decorator(func):def wrapper(*args, **kwargs):
# 添加新功能
result = func(*args, **kwargs)
# 添加新功能
return result
return wrapper
2. 关于装饰器的基础知识这一部分, 我们来到了第二小节, 也就是编号为2.1的函数基础知识回顾环节。
# 1. 函数是一等公民:可以赋值给变量def greet(name):
return f"Hello, {name}!"
say_hello = greet # 函数赋值给变量
print(say_hello("Alice")) # Hello, Alice!
# 2. 函数可以作为参数传递
def apply_function(func, value):
return func(value)
def square(x):
return x * x
print(apply_function(square, 5)) # 25
# 3. 函数可以嵌套定义
def outer():
def inner():
return "Inner function"
return inner()
# 4. 闭包:函数可以记住它被创建时的环境
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
times_3 = make_multiplier(3)
print(times_3(4)) # 12
3. 针对基础级别的装饰器这一块内容, 我们展开详细讲解。
# 最简单的装饰器def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!
")
say_hello()
# 输出:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.
3.这是关于第二个部分的内容, 主要是讲解那些带有参数的函数装饰器。
def timer_decorator(func):import time
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} executed in {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer_decorator
def slow_function(seconds):
time.sleep(seconds)
return f"Slept for {seconds} seconds"
print(slow_function(2))
# 输出:
# slow_function executed in 2.0023 seconds
# Slept for 2 seconds
3.3 带参数的装饰器
def repeat(num_times):"""装饰器工厂函数,返回一个装饰器"""
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!
")
greet("Alice")
# 输出:
# Hello, Alice!
# Hello, Alice!
# Hello, Alice!
3.4 保留函数元信息
from functools import wrapsdef preserve_metadata_decorator(func):
@wraps(func) # 使用wraps保留原函数的元信息
def wrapper(*args, **kwargs):
"""包装函数的文档"""
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@preserve_metadata_decorator
def calculate_sum(a, b):
"""计算两个数的和"""
return a + b
print(calculate_sum.__name__) # calculate_sum(如果不使用wraps会是wrapper)
print(calculate_sum.__doc__) # 计算两个数的和
print(calculate_sum(3, 4)) # 7
4. 所谓类装饰器这一章节的内容, 其主题是讨论4.1部分, 也就是要把一个类当作装饰器来使用的情景。
class TimerDecorator:def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start_time = time.time()
result = self.func(*args, **kwargs)
end_time = time.time()
print(f"Execution time: {end_time - start_time:.4f} seconds")
return result
@TimerDecorator
def long_running_operation():
time.sleep(1)
return "Operation completed"
print(long_running_operation())
4.2 带参数的类装饰器
class RetryDecorator:def __init__(self, max_retries=3):
self.max_retries = max_retries
def __call__(self, func):
def wrapper(*args, **kwargs):
for attempt in range(self.max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == self.max_retries - 1:
raise
print(f"Attempt {attempt + 1} failed: {e}. Retrying...")
return None
return wrapper
@RetryDecorator(max_retries=3)
def unstable_function():
import random
if random.random() < 0.7:
raise ValueError("Random failure!
")
return "Success!
"
print(unstable_function())
5. 关于另外的一些装饰器的应用, 在章节的第五点第一个小标题部分, 提到了存在多个装饰器这样的状况。
def decorator1(func):@wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 1: Before")
result = func(*args, **kwargs)
print("Decorator 1: After")
return result
return wrapper
def decorator2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 2: Before")
result = func(*args, **kwargs)
print("Decorator 2: After")
return result
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!
")
say_hello()
# 输出:
# Decorator 1: Before
# Decorator 2: Before
# Hello!
# Decorator 2: After
# Decorator 1: After
# 注意:装饰器从下往上执行
5.第2部分要讲的是装饰器以及与类方法相关的这些内容。
def method_decorator(func):@wraps(func)
def wrapper(self, *args, **kwargs):
print(f"Calling method {func.__name__} on {self}")
return func(self, *args, **kwargs)
return wrapper
class Calculator:
def __init__(self, value=0):
self.value = value
@method_decorator
def add(self, x):
self.value += x
return self.value
@method_decorator
def multiply(self, x):
self.value *= x
return self.value
calc = Calculator(10)
print(calc.add(5)) # 15
print(calc.multiply(2)) # 30
6. 关于装饰器的应用示例第6点1, 也就是缓存这个装饰器。
from functools import lru_cache# 使用内置的lru_cache装饰器
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 自定义缓存装饰器
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
@memoize
def expensive_computation(x):
print(f"Computing for {x}...")
import time
time.sleep(1)
return x * x
print(expensive_computation(5)) # 会打印"Computing for 5..."
print(expensive_computation(5)) # 直接从缓存返回,不会打印
6.这是一个用于权限验证装饰器的条目。
def require_permission(permission):def decorator(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if permission not in user.get('permissions', []):
raise PermissionError(f"User lacks {permission} permission")
return func(user, *args, **kwargs)
return wrapper
return decorator
class UserManager:
@require_permission('admin')
def delete_user(self, user, target_user):
return f"User {target_user} deleted by {user['name']}"
@require_permission('editor')
def edit_content(self, user, content):
return f"Content edited by {user['name']}"
admin_user = {'name': 'Alice', 'permissions': ['admin', 'editor']}
editor_user = {'name': 'Bob', 'permissions': ['editor']}
regular_user = {'name': 'Charlie', 'permissions': []}
manager = UserManager()
print(manager.delete_user(admin_user, 'old_user')) # 正常执行
# print(manager.delete_user(editor_user, 'old_user')) # 抛出PermissionError
6.这第3项是关于日志装饰器的一个内容说明。
import loggingfrom datetime import datetime
logging.basicConfig(level=logging.INFO)
def log_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = datetime.now()
logging.info(f"Starting {func.__name__} at {start_time}")
try:
result = func(*args, **kwargs)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
logging.info(f"Finished {func.__name__} in {duration:.2f}s")
return result
except Exception as e:
logging.error(f"Error in {func.__name__}: {e}")
raise
return wrapper
@log_decorator
def process_data(data):
import time
time.sleep(0.5)
return [x * 2 for x in data]
print(process_data([1, 2, 3, 4, 5]))
6.第4部分是关于类型检查装饰器的内容。
def type_check(**types):def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# 检查位置参数
for i, (arg, (param_name, expected_type)) in enumerate(
zip(args, types.items())
):
if not isinstance(arg, expected_type):
raise TypeError(
f"Argument '{param_name}' must be {expected_type}, "
f"got {type(arg)}"
)
# 检查关键字参数
for param_name, value in kwargs.items():
if param_name in types and not isinstance(value, types[param_name]):
raise TypeError(
f"Argument '{param_name}' must be {types[param_name]}, "
f"got {type(value)}"
)
return func(*args, **kwargs)
return wrapper
return decorator
@type_check(x=int, y=int)
def add_numbers(x, y):
return x + y
print(add_numbers(5, 3)) # 8
# print(add_numbers(5, "3")) # 抛出TypeError
7. 关于装饰器的调试工作以及测试环节, 其中需要着重关注的是第7.1小节所涉及的如何对装饰器进行调试这一具体问题的展开说明。
def debug_decorator(func):@wraps(func)
def wrapper(*args, **kwargs):
print(f"[DEBUG] Calling {func.__name__}")
print(f"[DEBUG] Args: {args}")
print(f"[DEBUG] Kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"[DEBUG] {func.__name__} returned: {result}")
return result
return wrapper
@debug_decorator
def divide(a, b):
return a / b
divide(10, 2)
7.2 测试装饰器
import unittestdef validate_input(min_value=0, max_value=100):
def decorator(func):
@wraps(func)
def wrapper(value):
if not (min_value <= value <= max_value):
raise ValueError(
f"Value must be between {min_value} and {max_value}"
)
return func(value)
return wrapper
return decorator
@validate_input(min_value=0, max_value=100)
def process_score(score):
return "Pass" if score >= 60 else "Fail"
class TestDecorator(unittest.TestCase):
def test_valid_score(self):
self.assertEqual(process_score(75), "Pass")
self.assertEqual(process_score(45), "Fail")
def test_invalid_score(self):
with self.assertRaises(ValueError):
process_score(150)
with self.assertRaises(ValueError):
process_score(-10)
if __name__ == "__main__":
unittest.main()
8. 要避免出现, 在循环里面去定义装饰器的这样的操作行为。
# 陷阱:在循环中定义装饰器def create_decorators():
decorators = []
for i in range(3):
def my_decorator(func):
def wrapper():
print(f"Decorator {i}")
return func()
return wrapper
decorators.append(my_decorator)
return decorators # 所有装饰器都会打印"Decorator 2"
# 正确做法:使用闭包捕获变量
def create_decorator_fixed(n):
def my_decorator(func):
def wrapper():
print(f"Decorator {n}")
return func()
return wrapper
return my_decorator
9. 总结
装饰器是中强大且灵活的特性,它允许我们:
增强函数的功能, 意味着我们可以做到无需修改原始函数代码, 从而实现代码复用将通用功能封装在装饰器里面。这能够保持代码整洁, 把关注点进行分离, 使代码变得更易于维护。它有助于实现面向切面编程, 比如进行日志处理, 或者执行权限验证等等。
掌握装饰器需要理解: