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

embedded/2025/2/1 18:27:26/

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/embedded/158705.html

相关文章

开源的Text-to-SQL工具WrenAI

WrenAI是一个开源的Text-to-SQL工具,旨在通过自然语言交互界面,帮助用户更便捷地查询数据库。以下是对WrenAI的详细介绍: 一、主要功能 自然语言交互:用户可以通过对话方式提出问题,WrenAI能够理解和解析复杂的查询需…

开源音乐管理软件Melody

本文软件由网友 heqiusheng 推荐。不过好像已经是一年前了 😂 简介 什么是 Melody ? Melody 是你的音乐精灵,旨在帮助你更好地管理音乐。目前的主要能力是帮助你将喜欢的歌曲或者音频上传到音乐平台的云盘。 主要功能包括: 歌曲…

如何用函数去计算x年x月x日是(C#)

如何用函数去计算x年x月x日是? 由于现在人工智能的普及,我们往往会用计算机去算,或者去记录事情 1.计算某一年某一个月有多少天 2.计算某年某月某日是周几 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threadin…

「 机器人 」“控制权”在扑翼飞行器中的重要性及其优化挑战

前言 对于扑翼飞行器而言,“控制权”不仅决定其飞行稳定性,也决定其在高动态任务(如快速机动、障碍规避)中的表现能力。以下内容从控制目标和控制权的定义出发,阐述了控制权的重要作用及优化难点,并探讨了潜在的解决方案。 1. 控制目标 1.1 飞行稳定性 • 通过调节机翼的…

DeepSeek R1功能设计涉及的几个关键词

DeepSeek R1作为人工智能助手,其功能设计主要基于以下步骤: 字典过滤与词汇选择 使用蒸馏技术对候选词汇进行筛选和优化,确保选择的词汇与上下文语境相关且准确。候选词汇通过多源数据(如公开文档、专家分析等)进行训练…

Jenkins 的安装(详细教程)_jenkins安装

二、安装前准备 在安装 jenkins 之前要先确保电脑上是否已配置过 Java 的环境变量,可调出命令窗口(win R 再输入 cmd),通过 java -version 来检验 如果没有显示 Java 的版本信息,就需要先配置 Java 环境变量&#xf…

Android createScaledBitmap与Canvas通过RectF drawBitmap生成马赛克/高斯模糊(毛玻璃)对比,Kotlin

Android createScaledBitmap与Canvas通过RectF drawBitmap生成马赛克/高斯模糊(毛玻璃)对比,Kotlin import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.RectF …

剑指offer 字符串 持续更新中...

文章目录 1. 替换空格1.1 题目描述1.2 从前向后替换空格1.3 从后向前替换空格 持续更新中… 1. 替换空格 替换空格 1.1 题目描述 题目描述:将一个字符串s中的每个空格替换成“%20”。 示例: 输入:"We Are Happy" 返回&#xf…