装饰器是Python中一个非常强大且有用的功能,它允许我们以不修改原有函数代码的方式,扩展或增强函数的行为,装饰器就是一个返回函数的函数,它们常用于日志记录、性能测试、事务处理、权限校验等方面,下面我们就来详细了解下Python装饰器的相关知识。
装饰器的原理
在讲解装饰器之前,我们先来了解下Python中的函数,在Python中,函数是一等公民,这意味着函数与其他对象(如整数、字符串、列表等)一样,可以作为参数传递,也可以作为返回值,装饰器正是利用了这一特性。
装饰器的基本原理是使用闭包(闭包的概念本文不展开,感兴趣的读者可以自行查阅资料),闭包允许函数访问定义在全局作用域的变量,即使函数被返回或在其他作用域中被调用,以下是装饰器的基本结构:
def decorator(func): def wrapper(*args, **kwargs): # 在函数执行前,可以添加一些代码 result = func(*args, **kwargs) # 在函数执行后,可以添加一些代码 return result return wrapper
装饰器的使用方法
下面我们通过一个简单的例子来了解装饰器的使用方法,假设我们有一个计算两个数之和的函数:
def add(a, b): return a + b
现在我们想在不修改add函数代码的情况下,为其添加一个功能:在执行add函数前后,分别打印开始计算和计算完成的消息,这时,装饰器就派上用场了:
def logger(func): def wrapper(*args, **kwargs): print("开始计算...") result = func(*args, **kwargs) print("计算完成!") return result return wrapper @logger def add(a, b): return a + b 调用被装饰的函数 print(add(1, 2))
运行上述代码,输出结果如下:
开始计算... 计算完成! 3
可以看到,我们在不修改add函数代码的情况下,为其添加了打印消息的功能,这里的@logger是一个语法糖,它的作用等同于add = logger(add)。
装饰器进阶
1、带参数的装饰器
我们希望装饰器能接受一些参数,以实现更灵活的功能,下面是一个带参数的装饰器示例:
def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for i in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(times=3) def say_hello(): print("Hello!") say_hello()
运行上述代码,输出结果如下:
Hello! Hello! Hello!
2、保持原函数的元信息
在使用装饰器时,我们可能会遇到一个问题:被装饰后的函数,其元信息(如docstring、name、参数列表等)会发生改变,为了解决这个问题,Python提供了一个内置函数functools.wraps,它可以将被装饰函数的元信息复制到装饰后的函数上。
from functools import wraps def logger(func): @wraps(func) def wrapper(*args, **kwargs): print("开始计算...") result = func(*args, **kwargs) print("计算完成!") return result return wrapper @logger def add(a, b): """计算两个数的和""" return a + b print(add.__name__) # 输出:add print(add.__doc__) # 输出:计算两个数的和
装饰器是Python中一种非常有用的语法结构,它让我们可以在不修改原有函数代码的情况下,扩展或增强函数的功能,掌握装饰器,能让我们编写出更简洁、优雅的代码,在实际开发中,装饰器广泛应用于日志记录、性能测试、事务处理、权限校验等方面,希望通过本文的介绍,大家对Python装饰器有了更深入的了解。