Python装饰器:如何扩展和修改函数的功能
Python装饰器是一种用于扩展和修改函数功能的语法。它可以在不修改原始函数代码的情况下,通过包装函数的方式,在函数执行前后添加额外的功能。这种方式可以提供很大的灵活性,使我们能够轻松地修改和更新已有的函数,同时也使代码更具可读性和可维护性。
装饰器的实现方式非常简单,它本质上是一个函数,它接收一个函数作为输入,并返回一个新的函数作为输出。在返回的新函数中,我们可以添加任意额外的处理逻辑,包括修改函数输入、输出,添加日志、计时等功能。
下面是一个示例,其中定义了一个装饰器函数log_time,它接收一个函数作为输入,并返回一个新的函数。在返回的新函数中,我们首先打印当前时间,然后调用传入的函数,最后再次打印当前时间。这样就实现了一个简单的计时功能。
import time
def log_time(func):
def wrapper(*args, **kwargs):
print("Current time:", time.time())
result = func(*args, **kwargs)
print("Current time:", time.time())
return result
return wrapper
@log_time
def my_function():
time.sleep(1)
print("Function executed")
my_function()
输出结果为:
Current time: 1638530781.2071207 Function executed Current time: 1638530782.2102845
可以看到,装饰器log_time在函数my_function执行前后分别打印了当前时间,并计算了函数执行的时间消耗。
在实际应用中,装饰器经常用于添加日志、缓存、鉴权、限流等功能。下面我们来看一个实际的示例,使用装饰器实现一个简单的缓存功能。
def cache(func):
cache_dict = {}
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key in cache_dict:
print("Get result from cache")
return cache_dict[key]
result = func(*args, **kwargs)
cache_dict[key] = result
return result
return wrapper
@cache
def factorial(n):
if n == 0:
return 1
return n * factorial(n-1)
print(factorial(5))
print(factorial(5))
输出结果为:
120 Get result from cache 120
可以看到,装饰器cache在计算阶乘的过程中,将每次计算的结果缓存起来。当下次需要计算同样的阶乘时,直接从缓存中获取结果,减少了计算的时间消耗。
除了使用@符号来应用装饰器外,我们还可以手动将装饰器应用到函数上。例如,下面的代码等价于上述示例:
def factorial(n):
if n == 0:
return 1
return n * factorial(n-1)
factorial = cache(factorial)
print(factorial(5))
print(factorial(5))
在实际开发中,我们也可以使用多个装饰器嵌套来实现更复杂的功能扩展。装饰器的执行顺序与装饰器的位置相关,离函数定义越近的装饰器将越早执行。
def decorator1(func):
print("Decorator 1")
return func
def decorator2(func):
print("Decorator 2")
return func
@decorator1
@decorator2
def my_function():
print("Function executed")
my_function()
输出结果为:
Decorator 2 Decorator 1 Function executed
最后需要注意的一点是,装饰器会改变函数的属性,例如__name__和__doc__。为了避免这种情况,我们可以使用functools模块中的wraps装饰器来修复这些属性。
总的来说,装饰器是一种强大的工具,它能够扩展和修改函数的功能,提供更高级的编程方式。熟练掌握装饰器的使用,将有助于提升代码的可读性和可维护性,同时也使我们能够更加灵活地修改和更新函数的逻辑。
