Python3 【装饰器】避坑指南:常见错误解析

devtools/2025/2/2 4:28:00/

Python3 【装饰器】避坑指南:常见错误解析

在编写或使用 Python 装饰器时,可能会遇到一些典型的错误。以下是 15 种常见错误,分析出错原因并提供纠正方法,同时通过代码示例进行演示和说明。


1. 忘记调用被装饰的函数

错误原因:在装饰器中忘记调用被装饰的函数。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")# 忘记调用 func()return wrapper@decorator
def my_function():print("函数逻辑")my_function()

输出:

装饰器逻辑

纠正方法:确保在装饰器中调用被装饰的函数。

正确代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 调用被装饰的函数return wrapper@decorator
def my_function():print("函数逻辑")my_function()

输出:

装饰器逻辑
函数逻辑

2. 装饰器未返回包装函数

错误原因:装饰器没有返回包装函数。

错误代码:

python">def decorator(func):print("装饰器逻辑")# 忘记返回 wrapper@decorator
def my_function():print("函数逻辑")my_function()

输出:

装饰器逻辑
TypeError: 'NoneType' object is not callable

纠正方法:确保装饰器返回包装函数。

正确代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()return wrapper  # 返回 wrapper@decorator
def my_function():print("函数逻辑")my_function()

输出:

装饰器逻辑
函数逻辑

3. 未正确处理函数参数

错误原因:装饰器未正确处理被装饰函数的参数。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未传递参数return wrapper@decorator
def my_function(a, b):print(f"a + b = {a + b}")my_function(1, 2)

输出:

TypeError: wrapper() takes 0 positional arguments but 2 were given

纠正方法:使用 *args**kwargs 传递参数。

正确代码:

python">def decorator(func):def wrapper(*args, **kwargs):print("装饰器逻辑")func(*args, **kwargs)  # 正确传递参数return wrapper@decorator
def my_function(a, b):print(f"a + b = {a + b}")my_function(1, 2)

输出:

装饰器逻辑
a + b = 3

4. 装饰器破坏了原函数的元信息

错误原因:装饰器覆盖了原函数的 __name____doc__ 等元信息。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()return wrapper@decorator
def my_function():"""这是一个示例函数"""print("函数逻辑")print(my_function.__name__)  # 输出 wrapper
print(my_function.__doc__)   # 输出 None

输出:

wrapper
None

纠正方法:使用 functools.wraps 保留元信息。

正确代码:

python">from functools import wrapsdef decorator(func):@wraps(func)def wrapper():print("装饰器逻辑")func()return wrapper@decorator
def my_function():"""这是一个示例函数"""print("函数逻辑")print(my_function.__name__)  # 输出 my_function
print(my_function.__doc__)   # 输出 这是一个示例函数

输出:

my_function
这是一个示例函数

5. 装饰器嵌套顺序错误

错误原因:多个装饰器的嵌套顺序错误,导致逻辑混乱。

错误代码:

python">def decorator1(func):def wrapper():print("装饰器 1")func()return wrapperdef decorator2(func):def wrapper():print("装饰器 2")func()return wrapper@decorator1
@decorator2
def my_function():print("函数逻辑")my_function()

输出:

装饰器 1
装饰器 2
函数逻辑

纠正方法:调整装饰器的嵌套顺序。

正确代码:

python">@decorator2
@decorator1
def my_function():print("函数逻辑")my_function()

输出:

装饰器 2
装饰器 1
函数逻辑

6. 装饰器未正确处理返回值

错误原因:装饰器未返回被装饰函数的返回值。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未返回 func() 的结果return wrapper@decorator
def my_function():return "函数返回值"print(my_function())

输出:

装饰器逻辑
None

纠正方法:返回被装饰函数的结果。

正确代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")return func()  # 返回 func() 的结果return wrapper@decorator
def my_function():return "函数返回值"print(my_function())

输出:

装饰器逻辑
函数返回值

7. 装饰器未正确处理异常

错误原因:装饰器未正确处理被装饰函数抛出的异常。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未捕获异常return wrapper@decorator
def my_function():raise ValueError("函数出错")my_function()

输出:

装饰器逻辑
ValueError: 函数出错

纠正方法:捕获并处理异常。

正确代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")try:func()except ValueError as e:print(f"捕获异常: {e}")return wrapper@decorator
def my_function():raise ValueError("函数出错")my_function()

输出:

装饰器逻辑
捕获异常: 函数出错

8. 装饰器未正确处理类方法

错误原因:装饰器未正确处理类方法的 self 参数。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未传递 selfreturn wrapperclass MyClass:@decoratordef my_method(self):print("方法逻辑")obj = MyClass()
obj.my_method()

输出:

TypeError: wrapper() takes 0 positional arguments but 1 was given

纠正方法:使用 *args**kwargs 传递 self

正确代码:

python">def decorator(func):def wrapper(*args, **kwargs):print("装饰器逻辑")func(*args, **kwargs)return wrapperclass MyClass:@decoratordef my_method(self):print("方法逻辑")obj = MyClass()
obj.my_method()

输出:

装饰器逻辑
方法逻辑

9. 装饰器未正确处理静态方法

错误原因:装饰器未正确处理静态方法的特性。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()return wrapperclass MyClass:@decorator@staticmethoddef my_method():print("静态方法逻辑")MyClass.my_method()

输出:

TypeError: 'staticmethod' object is not callable

纠正方法:将装饰器放在 @staticmethod 上方。

正确代码:

python">class MyClass:@staticmethod@decoratordef my_method():print("静态方法逻辑")MyClass.my_method()

输出:

装饰器逻辑
静态方法逻辑

10. 装饰器未正确处理类装饰器

错误原因:类装饰器未实现 __call__ 方法。

错误代码:

python">class Decorator:def __init__(self, func):self.func = func@Decorator
def my_function():print("函数逻辑")my_function()

输出:

TypeError: 'Decorator' object is not callable

纠正方法:实现 __call__ 方法。

正确代码:

python">class Decorator:def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print("装饰器逻辑")return self.func(*args, **kwargs)@Decorator
def my_function():print("函数逻辑")my_function()

输出:

装饰器逻辑
函数逻辑

11. 装饰器未正确处理生成器函数

错误原因:装饰器未正确处理生成器函数的返回值。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未返回生成器return wrapper@decorator
def my_generator():yield 1yield 2for value in my_generator():print(value)

输出:

装饰器逻辑
TypeError: 'NoneType' object is not iterable

纠正方法:返回生成器对象。

正确代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")return func()  # 返回生成器return wrapper@decorator
def my_generator():yield 1yield 2for value in my_generator():print(value)

输出:

装饰器逻辑
1
2

12. 装饰器未正确处理异步函数

错误原因:装饰器未正确处理异步函数的 await

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()  # 未使用 awaitreturn wrapper@decorator
async def my_async_function():print("异步函数逻辑")import asyncio
asyncio.run(my_async_function())

输出:

RuntimeWarning: coroutine 'my_async_function' was never awaited

纠正方法:使用 await 调用异步函数。

正确代码:

python">def decorator(func):async def wrapper():print("装饰器逻辑")await func()  # 使用 awaitreturn wrapper@decorator
async def my_async_function():print("异步函数逻辑")import asyncio
asyncio.run(my_async_function())

输出:

装饰器逻辑
异步函数逻辑

13. 装饰器未正确处理类属性

错误原因:装饰器未正确处理类属性的访问。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()return wrapperclass MyClass:@decorator@propertydef my_property(self):return "属性值"obj = MyClass()
print(obj.my_property)

输出:

TypeError: 'property' object is not callable

纠正方法:将装饰器放在 @property 上方。

正确代码:

python">def decorator(func):def wrapper(*args, **kwargs):print("装饰器逻辑")return func(*args, **kwargs)return wrapperclass MyClass:@property@decoratordef my_property(self):return "属性值"obj = MyClass()
print(obj.my_property)

输出:

装饰器逻辑
属性值

14. 装饰器未正确处理类方法装饰器

错误原因:装饰器未正确处理类方法装饰器的特性。

错误代码:

python">def decorator(func):def wrapper():print("装饰器逻辑")func()return wrapperclass MyClass:@decorator@classmethoddef my_classmethod(cls):print("类方法逻辑")MyClass.my_classmethod()

输出:

TypeError: 'classmethod' object is not callable

纠正方法:将装饰器放在 @classmethod 上方。

正确代码:

python">def decorator(func):def wrapper(*args, **kwargs):print("装饰器逻辑")func(*args, **kwargs)return wrapperclass MyClass:@classmethod@decoratordef my_classmethod(cls):print("类方法逻辑")MyClass.my_classmethod()

输出:

装饰器逻辑
类方法逻辑

15. 装饰器未正确处理带参数的装饰器

错误原因:带参数的装饰器未正确处理嵌套函数。

错误代码:

python">def decorator_with_args(arg):def decorator(func):print(f"装饰器参数: {arg}")return func()  # 未返回 wrapperreturn decorator@decorator_with_args("参数值")
def my_function():print("函数逻辑")my_function()

输出:

装饰器参数: 参数值
函数逻辑

纠正方法:返回包装函数。

正确代码:

python">def decorator_with_args(arg):def decorator(func):def wrapper():print(f"装饰器参数: {arg}")return func()return wrapperreturn decorator@decorator_with_args("参数值")
def my_function():print("函数逻辑")my_function()

输出:

装饰器参数: 参数值
函数逻辑

以上是 15 种典型错误及其纠正方法。通过理解这些错误,可以更好地编写和使用装饰器。


http://www.ppmy.cn/devtools/155338.html

相关文章

React Router v6配置路由守卫

首先准备好以下页面 登录页:用户可以在此页面登录。 受保护页:只有登录的用户可以访问,否则会重定向到登录页。 公共页面:不需要鉴权,任何人都可以访问。 1. 安装依赖 首先,我们需要安装 react-router-do…

Java算法——排序

目录 引言1. 插入排序1.1 基本思想1.2 直接插入排序1.3 希尔排序 2. 选择排序2.1 基本思想2.2 直接选择排序2.3 直接选择排序变种2.4 堆排序 3. 交换排序3.1 基本思想3.2 冒泡排序3.3 快速排序3.3.1 快速排序的基本结构3.3.2 Hoare法3.3.3 挖坑法3.3.4 双指针法 3.4 快速排序非…

【ArcMap零基础训练营】02 MODIS数据的下载与处理

MODIS数据处理 230107直播录像 MODIS数据下载及处理 MODIS数据简介 中分辨率成像光谱仪(The Moderate Resolution Imaging Spectroradiometer ,MODIS)是地球观测系统(EOS)Terra和Aqua平台上的一个关键仪器,…

npm link 作用

一、npm link 的定义 npm link 是 npm 提供的一个命令,它的主要作用是在本地开发 npm 包时,将本地开发的包链接到全局的 node_modules 目录中,并且在另一个项目中也可以使用这个本地开发的包,就好像它是一个通过 npm install 安装…

Python 数据分析 - Matplotlib 绘图

Python 数据分析 - Matplotlib 绘图 简介绘图折线图单线多线子图 散点图直方图条形图纵置横置多条 饼图 简介 Matplotlib 是 Python 提供的一个绘图库,通过该库我们可以很容易的绘制出折线图、直方图、散点图、饼图等丰富的统计图,安装使用 pip install…

Elasticsearch:如何搜索含有复合词的语言

作者:来自 Elastic Peter Straer 复合词在文本分析和标记过程中给搜索引擎带来挑战,因为它们会掩盖词语成分之间的有意义的联系。连字分解器标记过滤器等工具可以通过解构复合词来帮助解决这些问题。 德语以其长复合词而闻名:Rindfleischetik…

一文读懂fgc之cms

一文读懂 fgc之cms-实战篇 1. 前言 线上应用运行过程中可能会出现内存使用率较高,甚至达到95仍然不触发fgc的情况,存在内存打满风险,持续触发fgc回收;或者内存占用率较低时触发了fgc,导致某些接口tp99,tp…

Python Flask教程

一、前言 Flask是一个用Python编写的轻量级的Web应用框架。 Flask基于WSGI(Web Server Gateway Interface)和 Jinja2 模板引擎,旨在帮助开发者快速、简便地创建 Web 应用。 Flask 被称为"微框架",因为它使用简单的核…