装饰器(Decorator)是 Python 中最常见也最实用的元编程技术,用于在不修改原函数代码的前提下,动态扩展函数或类的功能。本文小编与大家分享 Python 装饰器的相关知识。
元编程(Metaprogramming)是指编写能够操作程序自身或其他程序结构的编程范式,可在编译时或运行时动态生成、修改代码特性。 Python 元编程主要依靠装饰器、元类、描述符和反射这 4 种技术实现。元编程不是日常写业务逻辑用的,主要用在底层框架和复杂系统里。由于涉及高级编程,大家可先做简单了解,后续涉及相关知识再进行详细介绍。 |
一、基本概念
Python 装饰器是一种不修改原代码就能给函数加功能的工具,用符号 @ 就能轻松调用 。它本质上是一个函数,接收另一个函数作为参数,返回一个新的函数(通常是原函数的增强版本),常见应用场景包括:
日志记录:记录函数调用信息、参数和返回值;
性能统计:统计函数执行时间;
权限控制:限制函数访问权限;
缓存:缓存函数结果,提高性能。
【小编提示】 在 Python 中一切皆是对象(无论是整数、浮点数、字符串,还是函数、类、模块,甚至是模块中的属性,都被视为对象),所以函数可以像变量一样被传递、赋值和操作。装饰器正是利用了这一思想,它本身就是一个函数,它接收一个函数作为参数,并返回一个新的函数。 |
二、使用装饰器
装饰器通过 @装饰器名 语法应用在函数或方法定义之前。大家应该记得在类的方法定义时,使用内置装饰器 @staticmethod 定义静态方法,使用内置装饰器 @classmethod 装饰器定义类方法。
三、自定义函数装饰器
装饰器的核心思想是:用一个函数"包装"另一个函数,开发者可以根据需求自定义装饰器。下面用编程示例介绍如何自定义装饰器。
(一)定义简单装饰器
注意:在上例中 wrapper() 函数名并不是必须的。wrapper 只是一个约定俗成的内部函数命名,Python 语法并不强制要求使用这个名字。比如修改该函数名为 execFun,程序依然正常运行。
(二)定义带参数装饰器
如果函数有参数,需要在装饰器 wrapper() 中使用 *args, **kwargs 参数。前文已介绍,*args 和 **kwargs 是用于函数定义的特殊语法,允许传递可变数量的参数。它们分别用于传递位置参数和关键字参数。
四、多个装饰器叠加
多个装饰器可以叠加,多个装饰器在定义阶段从下到上依次包裹函数,调用阶段从上到下依次执行。
五、自定义类装饰器
除了函数,装饰器也可以作用于类。类装饰器接收一个类,并返回修改后的类或包装类。其作用在于:
增强类方法;
控制实例化过程;
实现单例、日志等功能。
自定义类装饰器需要实现 __init__() 方法和 __call__ 方法:
受文章篇幅所限,下面以一个编程示例演示自定义类装饰器,大家可以查阅文档或相关教程详细了解。
六、保持被装饰的函数元数据
当使用装饰器包装函数时,有时会丢失原始函数的名称和文档字符串等属性。为了解决这个问题,Python 的 functools 模块提供了一个名为 wraps 的装饰器。@functools.wraps 装饰器的主要目的是在创建一个装饰器时,保留被装饰函数的原始信息。
在 Python 中,函数是对象,__name__ 和 __doc__ 是其两个核心的内置属性,分别用于标识函数身份和存储文档说明 。 __name__:函数的名称(字符串)。由定义时的函数名决定,不可自动改变(除非手动赋值)。注意:不要与模块的 __name__ 混淆(模块运行时可能为 '__main__'),函数对象的 __name__ 始终是其定义时的标识符 。 __doc__:函数的文档字符串(docstring)。存储紧跟在函数定义后的第一行三引号注释内容,用于描述功能。若定义了文档字符串,__doc__ 返回该字符串;若未定义,则为 None 。
|
七、Python 内置装饰器
Python 提供了多个内置装饰器,用于简化代码、增强功能。常用装饰器包括:
@staticmethod:静态方法;
@classmethod:类方法;
@property:将方法转为属性;
@abstractmethod:抽象方法;
@functools.wraps:保留元信息;
@dataclass:自动生成方法;
......
相关详细信息可查阅官方文档或网络教程了解。
八、装饰器使用注意事项
装饰器是一种强大的特性,但在使用装饰器时,需要注意以下细节:
装饰器参数传递;
装饰器叠加使用需要注意执行顺序;
装饰器可改变函数行为,应注意逻辑处理;
过度使用装饰器会影响程序性能;
调试和测试可能更为复杂。