当前位置: 首页 > article >正文

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

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

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


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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        # 忘记调用 func()
    return wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑

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

正确代码:

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

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

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

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

错误代码:

def decorator(func):
    print("装饰器逻辑")
    # 忘记返回 wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

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

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

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper  # 返回 wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

3. 未正确处理函数参数

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

错误代码:

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 传递参数。

正确代码:

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__ 等元信息。

错误代码:

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 保留元信息。

正确代码:

from functools import wraps

def 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. 装饰器嵌套顺序错误

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

错误代码:

def decorator1(func):
    def wrapper():
        print("装饰器 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("装饰器 2")
        func()
    return wrapper

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

my_function()

输出:

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

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

正确代码:

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

my_function()

输出:

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

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未返回 func() 的结果
    return wrapper

@decorator
def my_function():
    return "函数返回值"

print(my_function())

输出:

装饰器逻辑
None

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

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        return func()  # 返回 func() 的结果
    return wrapper

@decorator
def my_function():
    return "函数返回值"

print(my_function())

输出:

装饰器逻辑
函数返回值

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未捕获异常
    return wrapper

@decorator
def my_function():
    raise ValueError("函数出错")

my_function()

输出:

装饰器逻辑
ValueError: 函数出错

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

正确代码:

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 参数。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未传递 self
    return wrapper

class MyClass:
    @decorator
    def my_method(self):
        print("方法逻辑")

obj = MyClass()
obj.my_method()

输出:

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

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

正确代码:

def decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        func(*args, **kwargs)
    return wrapper

class MyClass:
    @decorator
    def my_method(self):
        print("方法逻辑")

obj = MyClass()
obj.my_method()

输出:

装饰器逻辑
方法逻辑

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

class MyClass:
    @decorator
    @staticmethod
    def my_method():
        print("静态方法逻辑")

MyClass.my_method()

输出:

TypeError: 'staticmethod' object is not callable

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

正确代码:

class MyClass:
    @staticmethod
    @decorator
    def my_method():
        print("静态方法逻辑")

MyClass.my_method()

输出:

装饰器逻辑
静态方法逻辑

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

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

错误代码:

class Decorator:
    def __init__(self, func):
        self.func = func

@Decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

TypeError: 'Decorator' object is not callable

纠正方法:实现 __call__ 方法。

正确代码:

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("装饰器逻辑")
        return self.func(*args, **kwargs)

@Decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未返回生成器
    return wrapper

@decorator
def my_generator():
    yield 1
    yield 2

for value in my_generator():
    print(value)

输出:

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

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

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        return func()  # 返回生成器
    return wrapper

@decorator
def my_generator():
    yield 1
    yield 2

for value in my_generator():
    print(value)

输出:

装饰器逻辑
1
2

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未使用 await
    return wrapper

@decorator
async def my_async_function():
    print("异步函数逻辑")

import asyncio
asyncio.run(my_async_function())

输出:

RuntimeWarning: coroutine 'my_async_function' was never awaited

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

正确代码:

def decorator(func):
    async def wrapper():
        print("装饰器逻辑")
        await func()  # 使用 await
    return wrapper

@decorator
async def my_async_function():
    print("异步函数逻辑")

import asyncio
asyncio.run(my_async_function())

输出:

装饰器逻辑
异步函数逻辑

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

class MyClass:
    @decorator
    @property
    def my_property(self):
        return "属性值"

obj = MyClass()
print(obj.my_property)

输出:

TypeError: 'property' object is not callable

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

正确代码:

def decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        return func(*args, **kwargs)
    return wrapper


class MyClass:
    @property
    @decorator
    def my_property(self):
        return "属性值"

obj = MyClass()
print(obj.my_property)

输出:

装饰器逻辑
属性值

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

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

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

class MyClass:
    @decorator
    @classmethod
    def my_classmethod(cls):
        print("类方法逻辑")

MyClass.my_classmethod()

输出:

TypeError: 'classmethod' object is not callable

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

正确代码:

def decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        func(*args, **kwargs)
    return wrapper

class MyClass:
    @classmethod
    @decorator
    def my_classmethod(cls):
        print("类方法逻辑")

MyClass.my_classmethod()

输出:

装饰器逻辑
类方法逻辑

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

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

错误代码:

def decorator_with_args(arg):
    def decorator(func):
        print(f"装饰器参数: {arg}")
        return func()  # 未返回 wrapper
    return decorator

@decorator_with_args("参数值")
def my_function():
    print("函数逻辑")

my_function()

输出:

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

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

正确代码:

def decorator_with_args(arg):
    def decorator(func):
        def wrapper():
            print(f"装饰器参数: {arg}")
            return func()
        return wrapper
    return decorator

@decorator_with_args("参数值")
def my_function():
    print("函数逻辑")

my_function()

输出:

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

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


http://www.kler.cn/a/527460.html

相关文章:

  • Linux运维之Linux的安装和配置
  • 缩位求和——蓝桥杯
  • CSS核心
  • Python - Quantstats量化投资策略绩效统计包 - 详解
  • 指针(C语言)从0到1掌握指针,为后续学习c++打下基础
  • zsh安装插件
  • [EAI-023] FAST,机器人动作专用的Tokenizer,提高VLA模型的能力和训练效率
  • 如何在 ACP 中建模复合罐
  • GCC, Makefile, make, CMake, CMakeLists.txt
  • 分布式微服务系统架构第89集:kafka消费者
  • 吴恩达深度学习——有效运作神经网络
  • 【LLM】Ollama框架入门指北
  • jEasyUI 创建 CRUD 应用
  • 安卓安全访问配置说明network-security-config —未来之窗跨平台操作
  • 【搞定offer】远程医疗:健康科技领域,搞定医疗offer
  • 2501,编写dll
  • 大语言模型(LLM)模拟金融市场参与者行为
  • 离线大模型-通义千问
  • 栈和队列特别篇:栈和队列的经典算法问题
  • ### 2024 江西省赛题解(A,C,D,G,H,J,K,L) BEFI待补
  • qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记
  • 合并2个排序的链表
  • DeepSeek是什么,最近到底经历了什么?它能干什么?
  • 注册谷歌账号
  • Linux:多线程[2] 线程控制
  • 10.5 LangChain Model I/O 深度解析:如何用标准化接口打通大模型开发的“任督二脉”?