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

Python 中的装饰器是什么?

装饰器是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 wrapper
    return 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 result
    return wrapper

@log_function_call
def add(a, b):
    return a + b

result = add(3, 4)
print(f"结果是:{result}")

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

使用内置装饰器

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

class MyClass:
    @staticmethod
    def static_method():
        print("这是一个静态方法")

    @classmethod
    def class_method(cls):
        print(f"这是一个类方法,类名是 {cls.__name__}")

    @property
    def prop(self):
        return "这是一个属性"

MyClass.static_method()
MyClass.class_method()
obj = MyClass()
print(obj.prop)
日常开发中的使用建议
  1. 保持装饰器简单:装饰器应该尽量保持简单,只做一件事情。复杂的逻辑应该放在被装饰的函数中。

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

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

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

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


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

相关文章:

  • 异常处理(6)自定义异常
  • node.js基础学习-http模块-创建HTTP服务器、客户端(一)
  • pytest 通过实例讲清单元测试、集成测试、测试覆盖率
  • Envoy 源码解析(一):Envoy 整体架构、Envoy 的初始化
  • faiss库中ivf-sq(ScalarQuantizer,标量量化)代码解读-2
  • CentOS 7 安装部署 KVM
  • VOS3000历史话单的非法呼叫话单解决方案,IPSS模块安装详细说明,新增随机端口,新增海外功能,可大幅度提高安全性!
  • Kubeadm 安装 Kubernetes 高可用集群 v1.30.0
  • flink中barrier不对齐的原因和影响
  • Unity类银河战士恶魔城学习总结(P146 Delete Save file-P147 Encryption of save data删除数据和加密数据)
  • 软件测试丨Pytest生命周期与数据驱动
  • 下载安装Android Studio
  • C++模板(入门)
  • Go错误与日志处理—推荐实践
  • STM32F103系列单片机通用和复用I/O(GPIO)
  • 容器和它的隔离机制
  • linux模拟HID USB设备及wireshark USB抓包配置
  • 最小生成树-Prim与Kruskal算法
  • day25|leetCode 491.递增子序列,46.全排列 ,47.全排列 II
  • 算法——四数相加 二(leetcode454)
  • 预处理指令
  • Java线程同步Synchronized
  • Kadb中的ecpg编程
  • 如何开发历史题材游戏。
  • C++练级计划->《单例模式》懒汉和饿汉
  • 使用PHP实现用户权限控制系统