DAY 27 函数专题2:装饰器-2025.9.14
函数专题2:装饰器
知识点回顾:
- 装饰器的思想:进一步复用
- 函数的装饰器写法
- 注意内部函数的返回值
作业:
编写一个装饰器 logger,在函数执行前后打印日志信息(如函数名、参数、返回值)
笔记:
装饰器是 Python 中一种非常强大的代码复用机制,核心思想是 “在不修改原函数代码的前提下,为函数添加额外功能”。它就像给函数 “戴帽子”—— 帽子(装饰器)提供额外功能,而函数本身的逻辑保持不变。这种思想在实际开发中(比如日志记录、性能计时、权限校验等场景)非常实用。
1. 装饰器的思想:进一步复用
假设你有 10 个函数,现在需要给每个函数添加 “执行前打印开始信息,执行后打印结束信息” 的功能。如果逐个修改这 10 个函数,会产生大量重复代码。
装饰器的解决方案是:** 把这些重复的 “增强功能” 写成一个通用的装饰器,然后 “套” 在需要增强的函数上 **。这样既不用修改原函数,又能实现功能复用。
核心逻辑:
- 装饰器本身是一个函数(或类)
- 接收 “被装饰的函数” 作为参数
- 返回一个 “增强后的新函数”
- 新函数会调用原函数,并在调用前后添加额外逻辑
2. 函数的装饰器写法
装饰器的基本结构是嵌套函数(函数内部定义另一个函数),外层函数负责接收原函数,内层函数负责实现增强逻辑并调用原函数,最后外层函数返回内层函数。
基础示例:定义一个打印函数执行日志的装饰器
# 定义装饰器(外层函数)
def log_decorator(func):# 定义内层函数(增强后的函数)def wrapper():print(f"开始执行函数:{func.__name__}") # 额外功能:执行前打印func() # 调用原函数print(f"函数{func.__name__}执行结束\n") # 额外功能:执行后打印return wrapper # 返回内层函数# 使用装饰器:用@符号把装饰器“套”在函数上
@log_decorator
def add():print("执行加法运算...")@log_decorator
def multiply():print("执行乘法运算...")# 调用被装饰后的函数
add()
multiply()
关键语法:
@log_decorator
等价于add = log_decorator(add)
,即把原函数传给装饰器,再用返回的新函数覆盖原函数名。- 装饰器会在函数定义时就生效,而不是调用时。
3. 注意内部函数的返回值
如果被装饰的函数有返回值,装饰器的内层函数必须将原函数的返回值传递出去,否则会丢失返回值(默认返回None)。
示例:处理带返回值的函数
def log_decorator(func):def wrapper():print(f"开始执行{func.__name__}...")result = func() # 保存原函数的返回值print(f"{func.__name__}执行结束")return result # 传递返回值return wrapper@log_decorator
def calculate_sum():return 1 + 2 # 原函数有返回值# 调用函数
total = calculate_sum()
print(f"计算结果:{total}") # 如果wrapper不返回result,这里会打印None
为什么必须传递返回值?
内层函数wrapper
是最终被调用的函数,如果wrapper
不返回func()
的结果,那么调用calculate_sum()
时,实际得到的是wrapper()
的返回值(默认None
),原函数的返回值就会丢失。
进阶:装饰带参数的函数
如果被装饰的函数有参数,内层函数wrapper
需要用*args
和**kwargs
接收任意参数,并传递给原函数。
def log_decorator(func):# 用*args和**kwargs接收任意参数def wrapper(*args, **kwargs):print(f"开始执行{func.__name__},参数:{args}, {kwargs}")result = func(*args, **kwargs) # 传递参数给原函数print(f"{func.__name__}执行结束")return resultreturn wrapper@log_decorator
def add(a, b):return a + b@log_decorator
def greet(name, message="Hello"):return f"{message}, {name}!"print(add(3, 5))
print(greet("Alice", message="Hi"))
总结
- ** 装饰器思想: 不修改原函数代码,通过 “包装” 增强函数功能,实现代码复用。
- 基本写法 :嵌套函数(外层接收原函数,内层实现增强逻辑并返回),用
@装饰器
名简化调用。 - 内部函数返回值 **:必须返回原函数的执行结果(
return func(...)
),否则会丢失返回值。
装饰器在实际开发中应用广泛,比如:
- 日志记录(记录函数调用参数和结果)
- 性能计时(计算函数执行时间)
- 权限校验(调用函数前检查用户权限)
- 异常捕获(自动处理函数可能抛出的异常)
作业
编写一个装饰器 logger,在函数执行前后打印日志信息(如函数名、参数、返回值)
@loggerdef multiply(a, b):return a * bmultiply(2, 3)
输出:
开始执行函数 multiply,参数: (2, 3), {}
函数 multiply 执行完毕,返回值: 6
def logger(func):def wrapper(*args,**kwargs):print(f'开始执行函数{func.__name__},参数:{args},{kwargs}')result = func(*args,**kwargs)print(f'函数{func.__name__}执行完毕,返回值:{result}')return resultreturn wrapper@logger
def multiply(a, b):return a * bmultiply(2, 3)
开始执行函数multiply,参数:(2, 3),{}
函数multiply执行完毕,返回值:6
@浙大疏锦行