Python装饰器模式(Decarator Pattern)是一种编程模式,它允许我们在不修改现有代码的情况下为已有函数添加新的功能。在Python中,装饰器模式通常使用@符号来表示。装饰器本质上是一个高阶函数,它可以接受一个函数作为参数,返回一个新的函数作为结果。这个新函数拥有了原函数的功能,同时还添加了装饰器的功能。
装饰器模式的主要功能是增强已有函数的功能,例如添加日志、计时、缓存等功能。这样可以提高代码的复用性和可维护性。
优点:
缺点:
应用场景:
使用方式:
在应用程序开发中,装饰器模式经常用于日志、缓存、权限控制等方面。例如,可以为需要进行权限控制的函数添加一个装饰器函数,如果用户没有相应的权限,就会进行拦截。此外,它还可以用于在运行时动态修改函数的行为。
利用Python的函数闭包特性,在运行装饰器函数时,将原函数作为参数传递给装饰器函数。
装饰器函数内部定义一个新函数来包装原函数,并在新函数中添加装饰器的功能。
最后返回新函数,替代原函数。当调用原函数时,实际上调用的是新函数。
此时,新函数会首先执行装饰器的功能,然后再执行原函数的功能。
假设有一个函数 add
,其功能是将两个数字相加并返回结果。现在需要给这个函数添加计时功能,记录函数执行时间,可以使用装饰器模式实现。
装饰器函数示例代码如下:
这个装饰器函数接收一个函数作为参数,返回一个新的函数,用于包装原函数并添加计时功能。
使用装饰器函数对 add
函数进行装饰:
现在,调用 add
函数时,会自动执行装饰器函数中的计时功能。
import time
# 定义装饰器函数
def time_decarator(func): # 接收函数作为参数
# *args 和 **kwargs 分别表示接受不定数量的位置参数和关键字参数;
# 当函数的参数前面带有一个 * 号时,表示将多个参数打包成一个元组传入函数;
# 当参数前面带有两个 * 号时,表示将多个参数打包成一个字典传入函数。
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time} seconds to execute.")
return res
return wrapper # 返回新的函数:包装原函数并添加计时器
@time_decarator
def add(x, y):
return x + y
print(add(1, 2))
运行结果:
Function add took 0.0 seconds to execute.
3
以上代码的工作原理是,使用 @
符号将装饰器函数 timing_decorator
放在 add
函数定义之前。这样,在调用 add
函数时,会先执行装饰器函数 timing_decorator
,返回一个新的函数 wrapper
,这个新函数会记录函数的执行时间,并调用原函数 add
来实现加法操作。最后,新函数 wrapper
返回计算结果,并输出函数执行时间。
如果不使用 @
符号,可以直接在调用函数时手动进行函数装饰,示例代码如下:
def add(x, y):
return x + y
add = time_decorator(add)
这样,调用 add
函数时会先执行装饰器函数,返回一个新函数用于包装原函数并添加计时功能。
使用 Python 装饰器模式可以方便地实现函数添加日志功能,具体实现步骤如下:
1. 定义装饰器函数 logger
,该函数将会接收一个函数作为参数,然后返回一个新函数。定义了一个名为 logger
的装饰器函数,该函数接收一个函数 func
作为参数,并返回一个新的函数 wrapper
。
2. 在需要添加日志功能的函数上方添加 @logger
装饰器。将 logger
装饰器应用于 my_func
函数上方,表示对该函数添加日志功能。
3. 调用 my_func
函数,查看输出结果。
# 定义装饰器函数,实现添加日志功能
def logger(func):
def wrapper(*args, **kwargs):
print(f"Function {func.__name__} with args: {args} and kwargs {kwargs}")
return func(*args, **kwargs)
return wrapper
@logger
def my_func(a, b):
return a - b
print(my_func(2, 1))
在上面的代码中,我们调用了 my_func
函数,并传入了两个参数 2和 1
。由于 my_func
被 logger
装饰器修饰,因此在函数执行前会先输出一条日志,记录调用的函数名及其参数,然后再执行函数并返回结果。最后,我们将函数的返回值打印出来,输出结果为:
Function my_func with args: (2, 1) and kwargs {}
1
从输出结果可以看出,函数 my_func
被成功修饰,成功添加了日志功能。
使用 Python 装饰器模式可以方便地实现函数添加缓存功能,可以有效地提高程序的执行效率。具体实现步骤如下:
1. 定义装饰器函数 cache
,该函数将会接收一个函数作为参数,然后返回一个新函数。
定义了一个名为 cache
的装饰器函数,该函数接收一个函数 func
作为参数,并返回一个新的函数 wrapper
。在 wrapper
函数中,我们使用了一个字典 cache_map
来作为缓存,记录之前已经执行过的函数结果。具体实现逻辑如下:
2. 在需要添加缓存功能的函数上方添加 @cache
装饰器。
将 cache
装饰器应用于 my_func
函数上方,表示对该函数添加缓存功能。
3. 调用 my_func
函数多次,查看输出结果。
# 定义装饰器函数,实现添加缓存功能
def cache(func):
cache_map = {}
def wrapper(*args, **kwargs):
# 生成缓存的key
key = str(args) + str(kwargs)
# 查询缓存中是否已经有值,如果有,则直接返回缓存中的值
if key in cache_map:
return cache_map[key]
# 如果缓存中没有值,则调用函数,将结果存入缓存并返回
res = func(*args, **kwargs)
cache_map[key] = res
return res
return wrapper
@cache
def my_func(a, b):
return a + b
r1 = my_func(1,2)
r2 = my_func(1,2)
r3 = my_func(3,4)
print(r1,r2,r3)
在上面的代码中,我们多次调用 my_func
函数,并传入不同的参数。由于 my_func
被 cache
装饰器修饰,因此在函数执行前会先检查缓存是否存在相应的值,如果存在,则直接返回缓存中的值,否则执行函数并将结果存入缓存。最后,我们将函数的返回值打印出来,输出结果为:
3 3 7
从输出结果可以看出,函数 my_func
被成功修饰,成功添加了缓存功能。
第一次调用
my_func(1,2)
时,函数会执行并将结果 3 存入缓存;第二次调用
my_func(1,2)
时,函数直接从缓存中取出结果 3 并返回;第三次调用
my_func(3,4)
时,由于参数不同,函数会重新执行并将结果 7 存入缓存。
*args
和 **kwargs参数说明
在 Python 中,*args
和 **kwargs
分别表示接受不定数量的位置参数和关键字参数。
- 当函数的参数前面带有一个 * 号时,表示将多个参数打包成一个元组传入函数;
- 当参数前面带有两个 * 号时,表示将多个参数打包成一个字典传入函数。
在函数调用时,可以将一些额外的参数传递给这个函数,这些参数会被打包成一个元组和字典传入函数中,可以在函数内部访问和处理这些参数。
下面是一个使用 *args
和 **kwargs
的示例:
def my_func(*args, **kwargs):
print(args)
print(kwargs)
my_func(1, 2, a=3, b=4)
输出结果为:
(1, 2)
{'a': 3, 'b': 4}
在上面的示例中,函数 my_func
接受了不定数量的位置参数 *args
和不定数量的关键字参数 **kwargs
。在调用函数 my_func
时,传入了两个位置参数 1
和 2
,以及两个关键字参数 a=3
和 b=4
。在函数内部,args
参数将被打包为一个元组 (1, 2)
,而 kwargs
参数将被打包为一个字典 {'a': 3, 'b': 4}
。