
装饰器内部若未显式返回被修饰函数的执行结果,会导致原函数返回值变为none;正确做法是在wrapper中调用原函数后,立即return其结果,并确保装饰器本身返回wrapper函数。
装饰器内部若未显式返回被修饰函数的执行结果,会导致原函数返回值变为none;正确做法是在wrapper中调用原函数后,立即return其结果,并确保装饰器本身返回wrapper函数。
在Python中,装饰器本质上是一个接收函数作为参数、并返回新函数的高阶函数。一个常见且隐蔽的错误是:在装饰器的内部包装函数(wrapper)中调用了原函数,却忘记返回其结果——这将导致无论原函数逻辑如何,最终调用结果恒为 None。
以问题中的日志装饰器为例:
def logger_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}")
result = func(*args, **kwargs)
# ❌ 缺少 return result → wrapper 默认返回 None
return wrapper # ✅ 正确:返回 wrapper 函数对象
虽然 wrapper 内部执行了 func(*args, **kwargs) 并将结果赋给了 result,但由于没有 return result 语句,wrapper 在执行完毕后隐式返回 None,因此 add(2, 3) 的调用结果就是 None,而非预期的 5。
✅ 正确实现如下:
def logger_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}")
result = func(*args, **kwargs)
return result # ✅ 显式返回原函数结果
return wrapper
@logger_decorator
def add(x, y):
return x + y
print(add(2, 3)) # 输出:
# Calling add with (2, 3)
# 5
⚠️ 注意事项:
- 使用
func.__name__而非func.name(后者会引发AttributeError); - 若需保留原函数的元信息(如文档字符串、签名等),建议使用
functools.wraps包装wrapper:from functools import wraps def logger_decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"Calling {func.__name__} with {args}") return func(*args, **kwargs) return wrapper - 所有装饰器都应遵循“调用原函数 → 捕获结果 → 返回结果”这一基本范式,中间可插入日志、计时、权限校验等逻辑,但不得中断返回链。
总结:装饰器不是“增强副作用”的黑盒,而是函数行为的代理;wrapper 的返回值即为被装饰函数对外暴露的返回值。漏写 return 是导致 None 意外返回的最常见原因,务必逐层检查返回路径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











