Python 中的装饰器是什么?

news/2024/11/28 21:34:02/

装饰器是Python中一种非常强大的功能,它允许你在不修改原始函数代码的前提下,增加额外的功能或改变函数的行为。

装饰器本质上是一个接受函数作为参数的函数,并返回一个新的函数。

通过装饰器,我们可以轻松地实现诸如日志记录、性能测试、事务处理等功能。

基本概念

装饰器的核心思想是通过一个高阶函数来增强或修改另一个函数的行为。一个简单的装饰器示例如下:

def my_decorator(func):def wrapper():print("在函数执行前做一些事情")func()print("在函数执行后做一些事情")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()

在这个例子中,my_decorator 是一个装饰器函数,它接受一个函数 func 作为参数,并返回一个新的函数 wrapper。当我们使用 @my_decorator 装饰 say_hello 函数时,实际上是在调用 my_decorator(say_hello),并将返回的 wrapper 函数赋值给 say_hello

带参数的装饰器

有些情况下,我们需要传递参数给装饰器本身。这可以通过再包裹一层函数来实现:

def repeat(num_times):def decorator(func):def wrapper():for _ in range(num_times):func()return wrapperreturn decorator@repeat(3)
def greet():print("你好!")greet()

在这个例子中,repeat 是一个接受参数 num_times 的函数,它返回一个真正的装饰器 decoratordecorator 接受函数 func 作为参数,并返回一个新的函数 wrapperwrapper 函数会在调用 func 时重复执行 num_times 次。

装饰带有参数的函数

如果被装饰的函数本身带有参数,我们需要在 wrapper 函数中传递这些参数:

def log_function_call(func):def wrapper(*args, **kwargs):print(f"调用函数 {func.__name__},参数为:{args}, {kwargs}")result = func(*args, **kwargs)print(f"函数 {func.__name__} 返回值为:{result}")return resultreturn wrapper@log_function_call
def add(a, b):return a + bresult = add(3, 4)
print(f"结果是:{result}")

在这个例子中,log_function_call 装饰器会在调用 add 函数前后打印相关信息。wrapper 函数使用 *args**kwargs 来接收任意数量的位置参数和关键字参数,并将它们传递给 func

使用内置装饰器

Python 提供了一些内置的装饰器,如 @staticmethod@classmethod@property,这些装饰器用于修改类方法的行为:

class MyClass:@staticmethoddef static_method():print("这是一个静态方法")@classmethoddef class_method(cls):print(f"这是一个类方法,类名是 {cls.__name__}")@propertydef prop(self):return "这是一个属性"MyClass.static_method()
MyClass.class_method()
obj = MyClass()
print(obj.prop)
日常开发中的使用建议
  1. 保持装饰器简单:装饰器应该尽量保持简单,只做一件事情。复杂的逻辑应该放在被装饰的函数中。

  2. 使用 functools.wraps:为了保持被装饰函数的元数据(如函数名、文档字符串等),可以使用 functools.wraps

    from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print("在函数执行前做一些事情")result = func(*args, **kwargs)print("在函数执行后做一些事情")return resultreturn wrapper@my_decorator
    def say_hello():"""这是一个打招呼的函数"""print("Hello!")print(say_hello.__name__)  # 输出: say_hello
    print(say_hello.__doc__)   # 输出: 这是一个打招呼的函数
  3. 避免过度使用装饰器:虽然装饰器非常强大,但过度使用会导致代码难以理解。只有在确实需要增强或修改函数行为时才使用装饰器。

  4. 测试装饰器:像测试普通函数一样测试装饰器,确保它们按预期工作。可以使用单元测试框架(如 unittestpytest)来编写测试用例。

  5. 考虑性能影响:装饰器可能会引入额外的开销,特别是在高频率调用的场景中。如果性能敏感,需要仔细评估装饰器的影响。


http://www.ppmy.cn/news/1550731.html

相关文章

Axios案例练习

使用原生的Ajax请求还是比较繁琐,所以说一般使用Axios,Axios是对于Ajax的封装,主要是为了简化书写。 Axios使用比较简单,主要分为两步: 1.在script标签的src中引入Axios文件 特别注意,这里是需要一对单独的…

java——Tomcat调优策略

Tomcat 作为一款广泛使用的 Java 应用服务器,其性能优化对于提高应用的响应速度和处理能力至关重要。优化方案可以从多个方面入手,包括但不限于内存优化、并发优化、连接器优化、JVM 调优、系统内核参数优化等。以下是这些优化方案的具体操作步骤&#x…

大模型智能客服系统是什么?

大模型智能客服系统是什么? 作者:开源大模型智能客服系统 FreeIPCC,Github地址:https://github.com/lihaiya/freeipcc,致力于成为大模型呼叫中心系统、电话机器人、智能呼叫中心系统、大模型智能客服系统;…

新能源整车厂车联网安全:架构、流程与融合

摘要: 本文从车联网安全工程师的视角出发,深入探讨新能源整车厂软件开发部门中车联网安全部门的角色与职责。详细阐述了关注组织架构和交付路径的重要性,并剖析如何将安全需求有效融入整车软件开发流程,涵盖基础软件、上层业务开发…

非线性控制器设计原理

非线性控制器设计原理 非线性控制器设计旨在解决非线性系统的控制问题,克服传统线性控制器在处理非线性现象(如饱和、死区、耦合、时变性等)时的不足。其核心在于利用非线性数学工具和设计方法,使控制系统在非线性条件下具备良好…

vue组件的基础功能使用

简单的组件分页 首先的是分页组件写好之后使用 :data进行数据绑定,mydata是请求过来的数据源,之后如果需要搜索什么的过滤可以替换,后面的内容currentpage4是页数,pagesize是每页多少条数据 如果需要输入框输入内容实时搜索 可以使用comput…

Java基于SSM框架的校园综合服务小程序【附源码、文档】

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…

李宏毅机器学习课程知识点摘要(14-18集)

线性回归,逻辑回归(线性回归sigmoid),神经网络 linear regression , logistic regression , neutral network 里面的偏导的相量有几百万维,这就是neutral network的不同,他是…