函数的装饰器:如何扩展和修改已有函数
函数的装饰器是Python中一种重要的编程技巧,可以实现在不修改已有函数源码的情况下,对函数的功能进行扩展和修改。本文将从以下几个方面介绍函数的装饰器:装饰器的定义和使用、常见的装饰器实现方式以及实际应用案例。
一、装饰器的定义和使用
装饰器本质上是一个可以接受一个函数作为参数,并返回一个新函数的函数。装饰器可以用来给函数增加新的功能,比如:计时器、缓存、参数验证等。
通过使用@符号和装饰器函数名称,可以让装饰器对目标函数进行装饰,示例如下:
def my_decorator(func): # 定义一个装饰器函数
def wrapper(): # 定义一个包装函数
print("Before function is called.")
func()
print("After function is called.")
return wrapper # 返回包装函数
@my_decorator # 使用@符号和装饰器函数名称,将函数进行装饰
def say_hello():
print("Hello!")
say_hello() # 调用被装饰的函数
执行结果:
Before function is called. Hello! After function is called.
在上面的示例中,@my_decorator语句将装饰器应用于say_hello函数。当调用say_hello函数时,其实是调用了装饰器中的wrapper函数,wrapper函数在调用原始函数say_hello之前和之后添加了额外的功能。
二、常见的装饰器实现方式
常见的装饰器实现方式有:函数嵌套、函数装饰器类、类装饰器等。
1. 函数嵌套
函数嵌套是最常见的装饰器实现方式,它是利用内函数的概念,在调用被装饰函数前后添加一些额外的功能。示例代码如下:
def time_it(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print("耗时:{}".format(end_time - start_time))
return result
return wrapper
@time_it
def my_function(input):
time.sleep(1)
return input
print(my_function("Hello, World!"))
在上面的示例中,time_it是一个装饰器函数,my_function是一个被装饰的函数。该装饰器使用time库计算函数的执行时间。
2. 函数装饰器类
函数装饰器类相比函数嵌套更加灵活,可以通过实例变量存储数据,并支持初始化和销毁方法。
示例代码如下:
class MyDecorator:
def __init__(self, func):
self.func = func
self.counter = 0
def __call__(self, *args, **kwargs):
self.counter += 1
result = self.func(*args, **kwargs)
print("调用次数:{}".format(self.counter))
return result
@MyDecorator
def my_function(input):
return input
print(my_function("Hello"))
print(my_function("World"))
在上面的示例中,MyDecorator是一个装饰器类,它维护了一个计数器变量。每次调用被装饰的函数,计数器就会加一。
3. 类装饰器
类装饰器指的是一个类对象可以作为装饰器来使用。类装饰器可以用于修改函数的参数、增加函数的属性等。
示例代码如下:
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
result = self.func(*args, **kwargs)
return "Decorator: " + result
@MyDecorator
def my_function(input):
return input
print(my_function("Hello, World!"))
在上面的示例中,MyDecorator是一个类装饰器,它在函数调用后返回一个新的字符串。
三、实际应用案例
1. 缓存装饰器
缓存装饰器可以将函数的计算结果缓存起来,在下次调用时直接返回缓存结果。这样可以减少函数重复计算。示例代码如下:
def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def fibonacci(n):
if n in (0, 1):
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10))
在上面的示例中,memoize是一个缓存装饰器,它使用一个字典存储缓存结果。当函数被调用时,装饰器首先判断缓存中是否有结果,有则直接返回,否则计算结果并将其存储在缓存中。
2. 参数检查装饰器
参数检查装饰器可以用来检查函数参数的有效性。如果参数无效,则抛出异常。示例代码如下:
def validate_args(*validators):
def decorator(func):
def wrapper(*args, **kwargs):
for validator in validators:
if not validator(*args, **kwargs):
raise ValueError(f"Invalid arguments: {args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_args(lambda x: isinstance(x, int),
lambda x: isinstance(x, int),
lambda x: x != 0)
def divide(a, b):
return a / b
print(divide(10, 2))
print(divide("hello", 2))
print(divide(10, 0))
在上面的示例中,validate_args是一个参数检查装饰器,它接受一个或多个参数检查函数作为输入。当函数被调用时,装饰器会检查其参数是否满足所有的参数检查函数。如果参数无效,则抛出异常。
四、总结
本文介绍了函数的装饰器的定义和使用,常见的装饰器实现方式以及实际应用案例。通过使用装饰器,我们可以很方便地扩展和修改已有的函数,从而使代码更加灵活、可维护。
